]> git.saurik.com Git - apple/syslog.git/commitdiff
syslog-322.tar.gz os-x-1011 os-x-10111 os-x-10112 v322
authorApple <opensource@apple.com>
Wed, 15 Jul 2015 22:30:37 +0000 (22:30 +0000)
committerApple <opensource@apple.com>
Wed, 15 Jul 2015 22:30:37 +0000 (22:30 +0000)
52 files changed:
aslcommon/asl_common.c
aslcommon/asl_common.h
aslcommon/asl_memory.c
aslcommon/asl_memory.h
aslmanager.tproj/aslmanager.c
aslmanager.tproj/cache_delete.c [new file with mode: 0644]
aslmanager.tproj/cache_delete.h [new file with mode: 0644]
aslmanager.tproj/com.apple.activity_tracing.CacheDelete.plist [new file with mode: 0644]
aslmanager.tproj/com.apple.aslmanager.plist
aslmanager.tproj/daemon.c [new file with mode: 0644]
aslmanager.tproj/daemon.h [new file with mode: 0644]
libsystem_asl.tproj/include/asl.h
libsystem_asl.tproj/include/asl_client.h
libsystem_asl.tproj/include/asl_core.h
libsystem_asl.tproj/include/asl_file.h
libsystem_asl.tproj/include/asl_msg.h
libsystem_asl.tproj/include/asl_private.h
libsystem_asl.tproj/man/asl.3
libsystem_asl.tproj/src/asl.c
libsystem_asl.tproj/src/asl_client.c
libsystem_asl.tproj/src/asl_core.c
libsystem_asl.tproj/src/asl_file.c
libsystem_asl.tproj/src/asl_msg.c
libsystem_asl.tproj/src/asl_object.c
libsystem_asl.tproj/src/asl_store.c
libsystem_asl.tproj/src/asl_string.c
libsystem_asl.tproj/src/asl_util.c
libsystem_asl.tproj/src/syslog.c
syslog.xcodeproj/project.pbxproj
syslogd.tproj/after_install.sh
syslogd.tproj/asl.conf.5
syslogd.tproj/asl.conf.ios [new file with mode: 0644]
syslogd.tproj/asl.conf.ios_sim [new file with mode: 0644]
syslogd.tproj/asl.conf.osx [new file with mode: 0644]
syslogd.tproj/asl_action.c
syslogd.tproj/asl_sim.conf [deleted file]
syslogd.tproj/bsd_out.c
syslogd.tproj/com.apple.system.log [new file with mode: 0644]
syslogd.tproj/daemon.c
syslogd.tproj/daemon.h
syslogd.tproj/dbserver.c
syslogd.tproj/remote.c
syslogd.tproj/syslog.conf [new file with mode: 0644]
syslogd.tproj/syslogd.c
syslogd.tproj/udp_in.c
util.tproj/syslog.1
util.tproj/syslog.c
xcodeconfig/aslmanager.xcconfig
xcodeconfig/base.xcconfig
xcodeconfig/libasl.xcconfig
xcodeconfig/syslogd.xcconfig
xcodeconfig/util.xcconfig

index fea5e91b6c63892c9855a93cb54738bba06c5d8a..ebe75c4da92ca9d903ecebec78809cf32f04f6b9 100644 (file)
@@ -2,14 +2,14 @@
  * Copyright (c) 2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * Copyright (c) 2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#include <assert.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdbool.h>
@@ -56,6 +55,8 @@
 #define _PATH_ASL_CONF_LOCAL_DIR "/usr/local/etc/asl"
 #endif
 
 #define _PATH_ASL_CONF_LOCAL_DIR "/usr/local/etc/asl"
 #endif
 
+//#define DEBUG_LIST_FILES 1
+
 static const char *asl_out_action_name[] =
 {
        "none         ",
 static const char *asl_out_action_name[] =
 {
        "none         ",
@@ -83,12 +84,6 @@ static const char *asl_out_action_name[] =
 #define forever for(;;)
 #define KEYMATCH(S,K) ((strncasecmp(S, K, strlen(K)) == 0))
 
 #define forever for(;;)
 #define KEYMATCH(S,K) ((strncasecmp(S, K, strlen(K)) == 0))
 
-#define STAMP_STYLE_INVALID -1
-#define STAMP_STYLE_NULL 0
-#define STAMP_STYLE_SEC 1
-#define STAMP_STYLE_SEQ 2
-#define STAMP_STYLE_UTC_OR_LCL 3
-
 asl_msg_t *
 xpc_object_to_asl_msg(xpc_object_t xobj)
 {
 asl_msg_t *
 xpc_object_to_asl_msg(xpc_object_t xobj)
 {
@@ -231,7 +226,7 @@ _insert_string(char *s, char **l, uint32_t x)
        int i, len;
 
        if (s == NULL) return l;
        int i, len;
 
        if (s == NULL) return l;
-       if (l == NULL) 
+       if (l == NULL)
        {
                l = (char **)malloc(2 * sizeof(char *));
                if (l == NULL) return NULL;
        {
                l = (char **)malloc(2 * sizeof(char *));
                if (l == NULL) return NULL;
@@ -249,7 +244,7 @@ _insert_string(char *s, char **l, uint32_t x)
 
        for (i = 0; l[i] != NULL; i++);
 
 
        for (i = 0; l[i] != NULL; i++);
 
-        /* len includes the NULL at the end of the list */
+       /* len includes the NULL at the end of the list */
        len = i + 1;
 
        l = (char **)reallocf(l, (len + 1) * sizeof(char *));
        len = i + 1;
 
        l = (char **)reallocf(l, (len + 1) * sizeof(char *));
@@ -443,8 +438,8 @@ next_word_from_string(char **s)
        return out;
 }
 
        return out;
 }
 
-static asl_out_dst_data_t *
-_asl_out_dest_for_path(asl_out_module_t *m, const char *path)
+asl_out_dst_data_t *
+asl_out_dest_for_path(asl_out_module_t *m, const char *path)
 {
        if (m == NULL) return NULL;
        if (path == NULL) return NULL;
 {
        if (m == NULL) return NULL;
        if (path == NULL) return NULL;
@@ -454,7 +449,7 @@ _asl_out_dest_for_path(asl_out_module_t *m, const char *path)
                asl_out_rule_t *r = m->ruleset;
                while (r != NULL)
                {
                asl_out_rule_t *r = m->ruleset;
                while (r != NULL)
                {
-                       if ((r->action == ACTION_OUT_DEST) && (r->dst != NULL) && (r->dst->path != NULL) && (!strcmp(r->dst->path, path))) return r->dst;
+                       if ((r->action == ACTION_OUT_DEST) && (r->dst != NULL) && (r->dst->path != NULL) && (streq(r->dst->path, path))) return r->dst;
                        r = r->next;
                }
 
                        r = r->next;
                }
 
@@ -538,7 +533,7 @@ _asl_common_make_dir_path(asl_out_module_t *mlist, uint32_t flags, const char *p
                        return -1;
                }
 
                        return -1;
                }
 
-               dst = _asl_out_dest_for_path(mlist, tmp);
+               dst = asl_out_dest_for_path(mlist, tmp);
                if ((dst == NULL) && (flags & MODULE_FLAG_NONSTD_DIR))
                {
                        /* no rule to create a non-standard path component! */
                if ((dst == NULL) && (flags & MODULE_FLAG_NONSTD_DIR))
                {
                        /* no rule to create a non-standard path component! */
@@ -616,6 +611,70 @@ asl_out_mkpath(asl_out_module_t *mlist, asl_out_rule_t *r)
        return -1;
 }
 
        return -1;
 }
 
+int
+asl_make_database_dir(const char *dir, char **out)
+{
+       const char *asldir, *path;
+       char *str = NULL;
+       struct stat sb;
+       int status;
+       mode_t mask;
+
+       if (out != NULL) *out = NULL;
+
+       asldir = asl_filesystem_path(ASL_PLACE_DATABASE);
+       if (asldir == NULL) return -1;
+
+       if (dir == NULL)
+       {
+               /* create the database directory itself */
+               path = asldir;
+       }
+       else
+       {
+               if (strchr(dir, '/') != NULL) return -1;
+
+               asprintf(&str, "%s/%s", asldir, dir);
+               if (str == NULL) return -1;
+               path = str;
+       }
+
+       memset(&sb, 0, sizeof(struct stat));
+
+       status = stat(path, &sb);
+       if (status == 0)
+       {
+               if (S_ISDIR(sb.st_mode))
+               {
+                       if (out == NULL) free(str);
+                       else *out = str;
+                       return 0;
+               }
+
+               free(str);
+               return -1;
+       }
+
+       if (errno != ENOENT)
+       {
+               free(str);
+               return -1;
+       }
+
+       mask = umask(0);
+       status = mkdir(path, 0755);
+       umask(mask);
+
+       if (status == 0)
+       {
+               if (out == NULL) free(str);
+               else *out = str;
+       }
+       else free(str);
+
+       return status;
+}
+
 void
 asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len)
 {
 void
 asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len)
 {
@@ -624,19 +683,19 @@ asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len)
 
        if (buf == NULL) return;
 
 
        if (buf == NULL) return;
 
-       if (flags & MODULE_FLAG_STYLE_UTC)
+       if (flags & MODULE_NAME_STYLE_STAMP_UTC)
        {
                memset(&t, 0, sizeof(t));
                gmtime_r(&stamp, &t);
                snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02dZ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
        }
        {
                memset(&t, 0, sizeof(t));
                gmtime_r(&stamp, &t);
                snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02dZ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
        }
-       else if (flags & MODULE_FLAG_STYLE_UTC_B)
+       else if (flags & MODULE_NAME_STYLE_STAMP_UTC_B)
        {
                memset(&t, 0, sizeof(t));
                gmtime_r(&stamp, &t);
                snprintf(buf, len, "%d%02d%02dT%02d%02d%02dZ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
        }
        {
                memset(&t, 0, sizeof(t));
                gmtime_r(&stamp, &t);
                snprintf(buf, len, "%d%02d%02dT%02d%02d%02dZ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
        }
-       else if (flags & MODULE_FLAG_STYLE_LCL)
+       else if (flags & MODULE_NAME_STYLE_STAMP_LCL)
        {
                bool neg = false;
                memset(&t, 0, sizeof(t));
        {
                bool neg = false;
                memset(&t, 0, sizeof(t));
@@ -654,7 +713,7 @@ asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len)
                else if (m > 0) snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02d%c%u:%02u", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, neg ? '-' : '+', h, m);
                else snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02d%c%u", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, neg ? '-' : '+', h);
        }
                else if (m > 0) snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02d%c%u:%02u", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, neg ? '-' : '+', h, m);
                else snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02d%c%u", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, neg ? '-' : '+', h);
        }
-       else if (flags & MODULE_FLAG_STYLE_LCL_B)
+       else if (flags & MODULE_NAME_STYLE_STAMP_LCL_B)
        {
                bool neg = false;
                memset(&t, 0, sizeof(t));
        {
                bool neg = false;
                memset(&t, 0, sizeof(t));
@@ -674,26 +733,37 @@ asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len)
        }
        else
        {
        }
        else
        {
-               snprintf(buf, len, "%c%lu", STYLE_SEC_PREFIX_CHAR, stamp);
+               snprintf(buf, len, "%c%llu", STYLE_SEC_PREFIX_CHAR, (unsigned long long)stamp);
        }
 }
 
 void
        }
 }
 
 void
-asl_make_dst_filename(asl_out_dst_data_t *dst, char *buf, size_t len)
+asl_dst_make_current_name(asl_out_dst_data_t *dst, uint32_t xflags, char *buf, size_t len)
 {
 {
+       char tstamp[32];
+
        if (dst == NULL) return;
        if (buf == NULL) return;
 
        if (dst == NULL) return;
        if (buf == NULL) return;
 
-       if (dst->flags & (MODULE_FLAG_BASESTAMP | MODULE_FLAG_TYPE_ASL_DIR))
-       {
-               char tstamp[32];
-               const char *name = dst->path;
+       xflags |= dst->flags;
 
 
-               if (dst->flags & MODULE_FLAG_TYPE_ASL_DIR) name = dst->fname;
+       if (dst->timestamp == 0) dst->timestamp = time(NULL);
+       asl_make_timestamp(dst->timestamp, dst->style_flags, tstamp, sizeof(tstamp));
 
 
-               if (dst->stamp == 0) dst->stamp = time(NULL);
-               asl_make_timestamp(dst->stamp, dst->flags, tstamp, sizeof(tstamp));
-               snprintf(buf, len, "%s.%s", name, tstamp);
+       if (xflags & MODULE_FLAG_TYPE_ASL_DIR)
+       {
+               snprintf(buf, len, "%s.%s", dst->current_name, tstamp);
+       }
+       else if (xflags & MODULE_FLAG_BASESTAMP)
+       {
+               if ((dst->dir != NULL) && (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE))
+               {
+                       snprintf(buf, len, "%s/%s.%s.%s", dst->dir, dst->base, tstamp, dst->ext);
+               }
+               else
+               {
+                       snprintf(buf, len, "%s.%s", dst->path, tstamp);
+               }
        }
        else
        {
        }
        else
        {
@@ -741,8 +811,11 @@ asl_out_dst_data_release(asl_out_dst_data_t *dst)
        if (dst->refcount > 0) dst->refcount--;
        if (dst->refcount > 0) return;
 
        if (dst->refcount > 0) dst->refcount--;
        if (dst->refcount > 0) return;
 
+       free(dst->dir);
        free(dst->path);
        free(dst->path);
-       free(dst->fname);
+       free(dst->current_name);
+       free(dst->base);
+       free(dst->ext);
        free(dst->rotate_dir);
        free(dst->fmt);
 #if !TARGET_IPHONE_SIMULATOR
        free(dst->rotate_dir);
        free(dst->fmt);
 #if !TARGET_IPHONE_SIMULATOR
@@ -886,11 +959,11 @@ asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp)
        if (dst == NULL) return -1;
        if (dst->path == NULL) return -1;
 
        if (dst == NULL) return -1;
        if (dst->path == NULL) return -1;
 
-       asl_make_dst_filename(dst, outpath, sizeof(outpath));
-       if (dst->fname != NULL) free(dst->fname);
+       asl_dst_make_current_name(dst, 0, outpath, sizeof(outpath));
+       free(dst->current_name);
 
 
-       dst->fname = strdup(outpath);
-       if (dst->fname == NULL) return -1;
+       dst->current_name = strdup(outpath);
+       if (dst->current_name == NULL) return -1;
 
        if (pathp != NULL) *pathp = strdup(outpath);
 
 
        if (pathp != NULL) *pathp = strdup(outpath);
 
@@ -904,10 +977,11 @@ asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp)
                /* file exists */
                fd = open(outpath, O_RDWR | O_APPEND | O_EXCL, 0);
 
                /* file exists */
                fd = open(outpath, O_RDWR | O_APPEND | O_EXCL, 0);
 
-               if (dst->stamp == 0) dst->stamp = sb.st_birthtimespec.tv_sec;
-               if (dst->stamp == 0) dst->stamp = sb.st_mtimespec.tv_sec;
+               if (dst->timestamp == 0) dst->timestamp = sb.st_birthtimespec.tv_sec;
+               if (dst->timestamp == 0) dst->timestamp = sb.st_mtimespec.tv_sec;
                dst->size = sb.st_size;
 
                dst->size = sb.st_size;
 
+               if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_FLAG_SYMLINK)) symlink(outpath, dst->path);
                return fd;
        }
        else if (errno != ENOENT)
                return fd;
        }
        else if (errno != ENOENT)
@@ -919,11 +993,18 @@ asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp)
        fd = open(outpath, O_RDWR | O_CREAT | O_EXCL, (dst->mode & 00666));
        if (fd < 0) return -1;
 
        fd = open(outpath, O_RDWR | O_CREAT | O_EXCL, (dst->mode & 00666));
        if (fd < 0) return -1;
 
-       dst->stamp = time(NULL);
+       dst->timestamp = time(NULL);
 
        fd = asl_out_dst_set_access(fd, dst);
        if (fd < 0) unlink(outpath);
 
 
        fd = asl_out_dst_set_access(fd, dst);
        if (fd < 0) unlink(outpath);
 
+       if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_FLAG_SYMLINK))
+       {
+               /* remove old symlink, make a new link to the "current" file */
+               unlink(dst->path);
+               symlink(outpath, dst->path);
+       }
+
        return fd;
 }
 
        return fd;
 }
 
@@ -1091,9 +1172,9 @@ _asl_out_module_parse_set_param(asl_out_module_t *m, char *s)
                else
                {
                        /* = param [query] */
                else
                {
                        /* = param [query] */
-                       if ((!strncmp(p, "[File ", 6)) || (!strncmp(p, "[File\t", 6))) out->action = ACTION_SET_FILE;
-                       else if ((!strncmp(p, "[Plist ", 7)) || (!strncmp(p, "[Plist\t", 7))) out->action = ACTION_SET_PLIST;
-                       else if ((!strncmp(p, "[Profile ", 9)) || (!strncmp(p, "[Profile\t", 9))) out->action = ACTION_SET_PROF;
+                       if (streq_len(p, "[File ", 6) || streq_len(p, "[File\t", 6)) out->action = ACTION_SET_FILE;
+                       else if (streq_len(p, "[Plist ", 7) || streq_len(p, "[Plist\t", 7)) out->action = ACTION_SET_PLIST;
+                       else if (streq_len(p, "[Profile ", 9) || streq_len(p, "[Profile\t", 9)) out->action = ACTION_SET_PROF;
 
                        p--;
                        *p = '\0';
 
                        p--;
                        *p = '\0';
@@ -1204,28 +1285,6 @@ _dst_format_string(char *s)
        return fmt;
 }
 
        return fmt;
 }
 
-size_t
-asl_str_to_size(char *s)
-{
-       size_t len, n, max;
-       char x;
-
-       if (s == NULL) return 0;
-
-       len = strlen(s);
-       if (len == 0) return 0;
-
-       n = 1;
-       x = s[len - 1];
-       if (x > 90) x -= 32;
-       if (x == 'K') n = 1ll << 10;
-       else if (x == 'M') n = 1ll << 20;
-       else if (x == 'G') n = 1ll << 30;
-
-       max = atoll(s) * n;
-       return max;
-}
-
 static bool
 _dst_path_match(const char *newpath, const char *existingpath)
 {
 static bool
 _dst_path_match(const char *newpath, const char *existingpath)
 {
@@ -1239,12 +1298,135 @@ _dst_path_match(const char *newpath, const char *existingpath)
        return (strcmp(newpath, trailing) == 0);
 }
 
        return (strcmp(newpath, trailing) == 0);
 }
 
+static uint32_t
+_parse_stamp_string(const char *in)
+{
+       char buf[16];
+       uint32_t x;
+
+       if (in == NULL) return 0;
+
+       for (x = 0; (((in[x] >= 'a') && (in[x] <= 'z')) || (in[x] == '-')) && (x < 11); x++) buf[x] = in[x];
+       buf[x] = '\0';
+
+       if (streq(buf, "sec") || streq(buf, "seconds")) return  MODULE_NAME_STYLE_STAMP_SEC;
+       if (streq(buf, "zulu") || streq(buf, "utc")) return MODULE_NAME_STYLE_STAMP_UTC;
+       if (streq(buf, "utc-b") || streq(buf, "utc-basic")) return MODULE_NAME_STYLE_STAMP_UTC_B;
+       if (streq(buf, "local") || streq(buf, "lcl")) return MODULE_NAME_STYLE_STAMP_LCL;
+       if (streq(buf, "local-b") || streq(buf, "lcl-b") || streq(buf, "local-basic") || streq(buf, "lcl-basic")) return MODULE_NAME_STYLE_STAMP_LCL_B;
+       if (streq(buf, "#") || streq(buf, "seq") || streq(buf, "sequence"))return MODULE_NAME_STYLE_STAMP_SEQ;
+
+       return 0;
+}
+
+/*
+ * Parse a file-rotation naming style.
+ *
+ * Legacy: sec / seconds, utc / date / zulu [-b], local / lcl [-b], # / seq / sequence
+ * We scan the whole line and match to one of these.
+ *
+ * New scheme: 2 or 3 components: base and style, or base, style, and extension.
+ * these define a name format.  base is the file name without a leading directory path
+ * and with no extension (e.g. "foo").  style is one of the styles above.  extension is
+ * the file name extension (e.g. "log", "txt", etc).
+ *
+ * Examples:
+ *     foo.utc.log
+ *     foo.log.lcl
+ *     foo.seq
+ *
+ * The leading base name may be ommitted (E.G. ".lcl.log", ".log.seq")
+ * If the leading base name AND extension are omitted, it is taken from the path.  E.G. ".lcl", ".seq"
+ *
+ * If we get input without a stamp spec, we default to "sec".
+ */
+static int
+_parse_dst_style(asl_out_dst_data_t *dst, const char *in)
+{
+       const char *p, *q;
+       size_t len;
+
+       if ((dst == NULL) || (in == NULL)) return -1;
+
+       /* check for base. or just . for shorthand */
+       p = NULL;
+       if (in[0] == '.')
+       {
+               p = in + 1;
+       }
+       else
+       {
+               if (dst->base == NULL) return -1;
+
+               len = strlen(dst->base);
+               if (streq_len(in, dst->base, len) && (in[len] == '.')) p = in + len + 1;
+       }
+
+       if (p == NULL)
+       {
+               /* input does not start with '.' or base, so this is legacy style */
+               dst->style_flags = _parse_stamp_string(in);
+               if (dst->style_flags == 0) return -1;
+
+               if (dst->ext == NULL) dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BS;
+               else dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BES;
+
+               return 0;
+       }
+
+       /* look for another dot in the name */
+       for (q = p; (*q != '.') && (*q != ' ') && (*q != '\t') && (*q != '\0'); q++);
+       if (*q != '.') q = NULL;
+
+       if (q == NULL)
+       {
+               /* we require a stamp spec, so we are expecting base.stamp */
+               dst->style_flags = _parse_stamp_string(p);
+
+               if (dst->style_flags == 0) return -1;
+
+               /*
+                * We got a valid stamp style ("base.stamp").
+                * Note that we might have skipped the extention if the file name was "foo.log".
+                * That's OK - syslogd writes "foo.log", but the rotated files are e.g. foo.20141018T1745Z.
+                */
+               dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BS;
+               return 0;
+       }
+
+       /* set q to the char past the dot */
+       q++;
+
+       /* either base.stamp.ext or base.ext.stamp */
+       if (dst->ext == NULL) return -1;
+
+       len = strlen(dst->ext);
+       if (streq_len(p, dst->ext, len) && (p[len] == '.'))
+       {
+               /* got base.ext.stamp */
+               dst->style_flags = _parse_stamp_string(q);
+               if (dst->style_flags == 0) return -1;
+
+               dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BES;
+               return 0;
+       }
+
+       /* must be base.stamp.ext */
+       if (strneq_len(q, dst->ext, len)) return -1;
+
+       dst->style_flags = _parse_stamp_string(p);
+       if (dst->style_flags == 0) return -1;
+
+       dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BSE;
+       return 0;
+}
+
 static asl_out_dst_data_t *
 _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
 {
        asl_out_rule_t *out, *rule;
        asl_out_dst_data_t *dst;
 static asl_out_dst_data_t *
 _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
 {
        asl_out_rule_t *out, *rule;
        asl_out_dst_data_t *dst;
-       char *p, *opts, *path;
+       char *p, *dot, *opts, *path;
        char **path_parts;
        int has_dotdot, recursion_limit;
        uint32_t i, flags = 0;
        char **path_parts;
        int has_dotdot, recursion_limit;
        uint32_t i, flags = 0;
@@ -1275,7 +1457,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
 
                for (i = 0; path_parts[i] != NULL; i++)
                {
 
                for (i = 0; path_parts[i] != NULL; i++)
                {
-                       if (!strncmp(path_parts[i], "$ENV(", 5))
+                       if (streq_len(path_parts[i], "$ENV(", 5))
                        {
                                char *p = strchr(path_parts[i], ')');
                                if (p != NULL) *p = '\0';
                        {
                                char *p = strchr(path_parts[i], ')');
                                if (p != NULL) *p = '\0';
@@ -1301,7 +1483,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
                                }
                        }
 
                                }
                        }
 
-                       if ((has_dotdot == 0) && (!strcmp(path_parts[i], ".."))) has_dotdot = 1;
+                       if ((has_dotdot == 0) && streq(path_parts[i], "..")) has_dotdot = 1;
                }
 
                free_string_list(path_parts);
                }
 
                free_string_list(path_parts);
@@ -1357,7 +1539,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
                if (log_root == NULL) log_root = "/tmp/log";
 #endif
 
                if (log_root == NULL) log_root = "/tmp/log";
 #endif
 
-               if (!strcmp(m->name, ASL_MODULE_NAME))
+               if (streq(m->name, ASL_MODULE_NAME))
                {
                        asprintf(&path, "%s/%s", log_root, t);
                }
                {
                        asprintf(&path, "%s/%s", log_root, t);
                }
@@ -1375,8 +1557,8 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
                 * Standard log directories get marked so that syslogd
                 * will create them without explicit rules.
                 */
                 * Standard log directories get marked so that syslogd
                 * will create them without explicit rules.
                 */
-               if (!strncmp(path, PATH_VAR_LOG, PATH_VAR_LOG_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR;
-               else if (!strncmp(path, PATH_LIBRARY_LOGS, PATH_LIBRARY_LOGS_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR;
+               if (streq_len(path, PATH_VAR_LOG, PATH_VAR_LOG_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR;
+               else if (streq_len(path, PATH_LIBRARY_LOGS, PATH_LIBRARY_LOGS_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR;
        }
 
        out = (asl_out_rule_t *)calloc(1, sizeof(asl_out_rule_t));
        }
 
        out = (asl_out_rule_t *)calloc(1, sizeof(asl_out_rule_t));
@@ -1391,10 +1573,37 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
 
        dst->refcount = 1;
        dst->path = path;
 
        dst->refcount = 1;
        dst->path = path;
+
+       p = strrchr(dst->path, '/');
+       if (p != NULL)
+       {
+               *p = '\0';
+               dst->dir = strdup(dst->path);
+               *p = '/';
+       }
+
        dst->mode = def_mode;
        dst->ttl[LEVEL_ALL] = DEFAULT_TTL;
        dst->flags = flags | MODULE_FLAG_COALESCE;
 
        dst->mode = def_mode;
        dst->ttl[LEVEL_ALL] = DEFAULT_TTL;
        dst->flags = flags | MODULE_FLAG_COALESCE;
 
+       /*
+        * Break out base and extension (if present) from path.
+        * Note this only supports a '.' as a separator.
+        */
+       p = strrchr(path, '/');
+       if (p == NULL) p = path;
+       else p++;
+
+       dot = strrchr(path, '.');
+       if (dot != NULL)
+       {
+               *dot = '\0';
+               dst->ext = strdup(dot + 1);
+       }
+
+       dst->base = strdup(p);
+       if (dot != NULL) *dot = '.';
+
        while (NULL != (p = next_word_from_string(&opts)))
        {
                if (KEYMATCH(p, "mode=")) dst->mode = strtol(p+5, NULL, 0);
        while (NULL != (p = next_word_from_string(&opts)))
        {
                if (KEYMATCH(p, "mode=")) dst->mode = strtol(p+5, NULL, 0);
@@ -1413,46 +1622,27 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
                        else if (KEYMATCH(p+9, "false")) dst->flags &= ~MODULE_FLAG_COALESCE;
                }
                else if (KEYMATCH(p, "compress")) dst->flags |= MODULE_FLAG_COMPRESS;
                        else if (KEYMATCH(p+9, "false")) dst->flags &= ~MODULE_FLAG_COALESCE;
                }
                else if (KEYMATCH(p, "compress")) dst->flags |= MODULE_FLAG_COMPRESS;
+               else if (KEYMATCH(p, "activity")) dst->flags |= MODULE_FLAG_ACTIVITY;
                else if (KEYMATCH(p, "extern")) dst->flags |= MODULE_FLAG_EXTERNAL;
                else if (KEYMATCH(p, "truncate")) dst->flags |= MODULE_FLAG_TRUNCATE;
                else if (KEYMATCH(p, "dir")) dst->flags |= MODULE_FLAG_TYPE_ASL_DIR;
                else if (KEYMATCH(p, "soft")) dst->flags |= MODULE_FLAG_SOFT_WRITE;
                else if (KEYMATCH(p, "extern")) dst->flags |= MODULE_FLAG_EXTERNAL;
                else if (KEYMATCH(p, "truncate")) dst->flags |= MODULE_FLAG_TRUNCATE;
                else if (KEYMATCH(p, "dir")) dst->flags |= MODULE_FLAG_TYPE_ASL_DIR;
                else if (KEYMATCH(p, "soft")) dst->flags |= MODULE_FLAG_SOFT_WRITE;
-               else if (KEYMATCH(p, "file_max=")) dst->file_max = asl_str_to_size(p+9);
-               else if (KEYMATCH(p, "all_max=")) dst->all_max = asl_str_to_size(p+8);
+               else if (KEYMATCH(p, "file_max=")) dst->file_max = asl_core_str_to_size(p+9);
+               else if (KEYMATCH(p, "all_max=")) dst->all_max = asl_core_str_to_size(p+8);
                else if (KEYMATCH(p, "style=") || KEYMATCH(p, "rotate="))
                {
                        const char *x = p + 6;
 
                else if (KEYMATCH(p, "style=") || KEYMATCH(p, "rotate="))
                {
                        const char *x = p + 6;
 
-                       if (KEYMATCH(p, "rotate=")) x++;
+                       if (*p == 'r') x++;
+                       if (_parse_dst_style(dst, x) == 0) dst->flags |= MODULE_FLAG_ROTATE;
+               }
+               else if (KEYMATCH(p, "rotate"))
+               {
+                       if (dst->ext == NULL) dst->style_flags = MODULE_NAME_STYLE_FORMAT_BS | MODULE_NAME_STYLE_STAMP_SEC;
+                       else dst->style_flags = MODULE_NAME_STYLE_FORMAT_BES | MODULE_NAME_STYLE_STAMP_SEC;
 
                        dst->flags |= MODULE_FLAG_ROTATE;
 
                        dst->flags |= MODULE_FLAG_ROTATE;
-
-                       if (KEYMATCH(x, "sec") || KEYMATCH(x, "seconds"))
-                       {
-                               dst->flags |= MODULE_FLAG_STYLE_SEC;
-                       }
-                       else if (KEYMATCH(x, "utc") || KEYMATCH(x, "date") || KEYMATCH(x, "zulu"))
-                       {
-                               const char *dash = strchr(x, '-');
-                               if ((dash != NULL) && (*(dash + 1) == 'b')) dst->flags |= MODULE_FLAG_STYLE_UTC_B;
-                               else dst->flags |= MODULE_FLAG_STYLE_UTC;
-                       }
-                       else if (KEYMATCH(x, "local") || KEYMATCH(x, "lcl"))
-                       {
-                               const char *dash = strchr(x, '-');
-                               if ((dash != NULL) && (*(dash + 1) == 'b')) dst->flags |= MODULE_FLAG_STYLE_LCL_B;
-                               else dst->flags |= MODULE_FLAG_STYLE_LCL;
-                       }
-                       else if (KEYMATCH(x, "#") || KEYMATCH(x, "seq") || KEYMATCH(x, "sequence"))
-                       {
-                               dst->flags |= MODULE_FLAG_STYLE_SEQ;
-                       }
-                       else
-                       {
-                               dst->flags |= MODULE_FLAG_STYLE_SEC;
-                       }
                }
                }
-               else if (KEYMATCH(p, "rotate")) dst->flags |= MODULE_FLAG_ROTATE;
                else if (KEYMATCH(p, "crashlog"))
                {
                        /* crashlog implies rotation */
                else if (KEYMATCH(p, "crashlog"))
                {
                        /* crashlog implies rotation */
@@ -1465,17 +1655,21 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
                {
                        dst->flags |= MODULE_FLAG_BASESTAMP;
                }
                {
                        dst->flags |= MODULE_FLAG_BASESTAMP;
                }
+               else if (KEYMATCH(p, "link") || KEYMATCH(p, "symlink"))
+               {
+                       dst->flags |= MODULE_FLAG_SYMLINK;
+               }
                else if (KEYMATCH(p, "ttl"))
                {
                        char *q = p + 3;
                        if (*q == '=')
                        {
                else if (KEYMATCH(p, "ttl"))
                {
                        char *q = p + 3;
                        if (*q == '=')
                        {
-                               dst->ttl[LEVEL_ALL] = strtol(p+4, NULL, 0);
+                               dst->ttl[LEVEL_ALL] = asl_core_str_to_time(p+4, SECONDS_PER_DAY);
                        }
                        else if ((*q >= '0') && (*q <= '7') && (*(q+1) == '='))
                        {
                                uint32_t x = *q - '0';
                        }
                        else if ((*q >= '0') && (*q <= '7') && (*(q+1) == '='))
                        {
                                uint32_t x = *q - '0';
-                               dst->ttl[x] = strtol(p+5, NULL, 0);
+                               dst->ttl[x] = asl_core_str_to_time(p+5, SECONDS_PER_DAY);
                        }
                }
 
                        }
                }
 
@@ -1485,7 +1679,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
 
 #if TARGET_OS_EMBEDDED
        /* check for crashreporter files */
 
 #if TARGET_OS_EMBEDDED
        /* check for crashreporter files */
-       if ((KEYMATCH(dst->path, _PATH_CRASHREPORTER)) || (KEYMATCH(dst->path, _PATH_CRASHREPORTER_MOBILE)))
+       if ((KEYMATCH(dst->path, _PATH_CRASHREPORTER)) || (KEYMATCH(dst->path, _PATH_CRASHREPORTER_MOBILE_1)) || (KEYMATCH(dst->path, _PATH_CRASHREPORTER_MOBILE_2)))
        {
                dst->flags |= MODULE_FLAG_ROTATE;
                dst->flags |= MODULE_FLAG_CRASHLOG;
        {
                dst->flags |= MODULE_FLAG_ROTATE;
                dst->flags |= MODULE_FLAG_CRASHLOG;
@@ -1504,24 +1698,27 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
        if (strcmp(dst->fmt, "std") && strcmp(dst->fmt, "bsd")) dst->flags &= ~MODULE_FLAG_COALESCE;
 
        /* note if format is one of std, bsd, or msg */
        if (strcmp(dst->fmt, "std") && strcmp(dst->fmt, "bsd")) dst->flags &= ~MODULE_FLAG_COALESCE;
 
        /* note if format is one of std, bsd, or msg */
-       if (!strcmp(dst->fmt, "std") || !strcmp(dst->fmt, "bsd") || !strcmp(dst->fmt, "msg")) dst->flags |= MODULE_FLAG_STD_BSD_MSG;
+       if (streq(dst->fmt, "std") || streq(dst->fmt, "bsd") || streq(dst->fmt, "msg")) dst->flags |= MODULE_FLAG_STD_BSD_MSG;
 
 
-       /* MODULE_FLAG_STYLE_SEQ can not be used with MODULE_FLAG_BASESTAMP */
-       if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_FLAG_STYLE_SEQ))
+       /* MODULE_NAME_STYLE_STAMP_SEQ can not be used with MODULE_FLAG_BASESTAMP */
+       if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_NAME_STYLE_STAMP_SEQ))
        {
        {
-               dst->flags &= ~MODULE_FLAG_STYLE_SEQ;
-               dst->flags |= MODULE_FLAG_STYLE_SEC;
+               dst->flags &= ~MODULE_NAME_STYLE_STAMP_SEQ;
+               dst->flags |= MODULE_NAME_STYLE_STAMP_SEC;
        }
 
        /* set time format for raw output */
        }
 
        /* set time format for raw output */
-       if (!strcmp(dst->fmt, "raw")) dst->tfmt = "sec";
+       if (streq(dst->fmt, "raw")) dst->tfmt = "sec";
 
        /* check for ASL_PLACE_DATABASE_DEFAULT */
 
        /* check for ASL_PLACE_DATABASE_DEFAULT */
-       if (!strcmp(dst->path, ASL_PLACE_DATABASE_DEFAULT))
+       if (streq(dst->path, ASL_PLACE_DATABASE_DEFAULT))
        {
                dst->flags = MODULE_FLAG_TYPE_ASL_DIR;
        }
 
        {
                dst->flags = MODULE_FLAG_TYPE_ASL_DIR;
        }
 
+       /* set file_max to all_max if it is zero */
+       if (dst->file_max == 0) dst->file_max = dst->all_max;
+
        out->action = ACTION_OUT_DEST;
        out->dst = dst;
 
        out->action = ACTION_OUT_DEST;
        out->dst = dst;
 
@@ -1551,29 +1748,29 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s)
        if (p == NULL) p = strchr(act, '\t');
        if (p != NULL) *p = '\0';
 
        if (p == NULL) p = strchr(act, '\t');
        if (p != NULL) *p = '\0';
 
-       if (!strcasecmp(act, "ignore"))               out->action = ACTION_IGNORE;
-       else if (!strcasecmp(act, "skip"))            out->action = ACTION_SKIP;
-       else if (!strcasecmp(act, "claim"))           out->action = ACTION_CLAIM;
-       else if (!strcasecmp(act, "notify"))          out->action = ACTION_NOTIFY;
-       else if (!strcasecmp(act, "file"))            out->action = ACTION_FILE;
-       else if (!strcasecmp(act, "asl_file"))        out->action = ACTION_ASL_FILE;
-       else if (!strcasecmp(act, "directory"))       out->action = ACTION_ASL_DIR;
-       else if (!strcasecmp(act, "dir"))             out->action = ACTION_ASL_DIR;
-       else if (!strcasecmp(act, "asl_directory"))   out->action = ACTION_ASL_DIR;
-       else if (!strcasecmp(act, "asl_dir"))         out->action = ACTION_ASL_DIR;
-       else if (!strcasecmp(act, "store_dir"))       out->action = ACTION_ASL_DIR;
-       else if (!strcasecmp(act, "store_directory")) out->action = ACTION_ASL_DIR;
-       else if (!strcasecmp(act, "control"))             out->action = ACTION_CONTROL;
-       else if (!strcasecmp(act, "save"))            out->action = ACTION_ASL_STORE;
-       else if (!strcasecmp(act, "store"))           out->action = ACTION_ASL_STORE;
-       else if (!strcasecmp(act, "access"))          out->action = ACTION_ACCESS;
-       else if (!strcasecmp(act, "set"))             out->action = ACTION_SET_KEY;
-       else if (!strcasecmp(act, "unset"))           out->action = ACTION_UNSET_KEY;
-       else if (!strcmp(m->name, ASL_MODULE_NAME))
+       if (strcaseeq(act, "ignore"))               out->action = ACTION_IGNORE;
+       else if (strcaseeq(act, "skip"))            out->action = ACTION_SKIP;
+       else if (strcaseeq(act, "claim"))           out->action = ACTION_CLAIM;
+       else if (strcaseeq(act, "notify"))          out->action = ACTION_NOTIFY;
+       else if (strcaseeq(act, "file"))            out->action = ACTION_FILE;
+       else if (strcaseeq(act, "asl_file"))        out->action = ACTION_ASL_FILE;
+       else if (strcaseeq(act, "directory"))       out->action = ACTION_ASL_DIR;
+       else if (strcaseeq(act, "dir"))             out->action = ACTION_ASL_DIR;
+       else if (strcaseeq(act, "asl_directory"))   out->action = ACTION_ASL_DIR;
+       else if (strcaseeq(act, "asl_dir"))         out->action = ACTION_ASL_DIR;
+       else if (strcaseeq(act, "store_dir"))       out->action = ACTION_ASL_DIR;
+       else if (strcaseeq(act, "store_directory")) out->action = ACTION_ASL_DIR;
+       else if (strcaseeq(act, "control"))                 out->action = ACTION_CONTROL;
+       else if (strcaseeq(act, "save"))            out->action = ACTION_ASL_STORE;
+       else if (strcaseeq(act, "store"))           out->action = ACTION_ASL_STORE;
+       else if (strcaseeq(act, "access"))          out->action = ACTION_ACCESS;
+       else if (strcaseeq(act, "set"))             out->action = ACTION_SET_KEY;
+       else if (strcaseeq(act, "unset"))           out->action = ACTION_UNSET_KEY;
+       else if (streq(m->name, ASL_MODULE_NAME))
        {
                /* actions only allowed in com.apple.asl */
        {
                /* actions only allowed in com.apple.asl */
-               if (!strcasecmp(act, "broadcast"))   out->action = ACTION_BROADCAST;
-               else if (!strcasecmp(act, "forward"))     out->action = ACTION_FORWARD;
+               if (strcaseeq(act, "broadcast"))    out->action = ACTION_BROADCAST;
+               else if (strcaseeq(act, "forward")) out->action = ACTION_FORWARD;
        }
 
        if (out->action == ACTION_NONE)
        }
 
        if (out->action == ACTION_NONE)
@@ -1622,7 +1819,7 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s)
        if (out->action == ACTION_ASL_STORE)
        {
                if (out->options == NULL) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, ASL_PLACE_DATABASE_DEFAULT, 0755));
        if (out->action == ACTION_ASL_STORE)
        {
                if (out->options == NULL) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, ASL_PLACE_DATABASE_DEFAULT, 0755));
-               else if (!strncmp(out->options, ASL_PLACE_DATABASE_DEFAULT, strlen(ASL_PLACE_DATABASE_DEFAULT))) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, out->options, 0755));
+               else if (streq_len(out->options, ASL_PLACE_DATABASE_DEFAULT, strlen(ASL_PLACE_DATABASE_DEFAULT))) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, out->options, 0755));
                else if (out->options != NULL) out->action = ACTION_ASL_FILE;
        }
 
                else if (out->options != NULL) out->action = ACTION_ASL_FILE;
        }
 
@@ -1644,7 +1841,7 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s)
                 */
                if (out->dst->mode == 010000) out->dst->mode = def_mode;
 
                 */
                if (out->dst->mode == 010000) out->dst->mode = def_mode;
 
-               if ((out->action == ACTION_FILE) && (out->dst != NULL) && (out->dst->fmt != NULL) && (!strcasecmp(out->dst->fmt, "asl")))
+               if ((out->action == ACTION_FILE) && (out->dst != NULL) && (out->dst->fmt != NULL) && (strcaseeq(out->dst->fmt, "asl")))
                {
                        out->action = ACTION_ASL_FILE;
                }
                {
                        out->action = ACTION_ASL_FILE;
                }
@@ -1659,13 +1856,10 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s)
                        /* coalesce is meaningless for ASL directories */
                        out->dst->flags &= ~MODULE_FLAG_COALESCE;
 
                        /* coalesce is meaningless for ASL directories */
                        out->dst->flags &= ~MODULE_FLAG_COALESCE;
 
-                       /* no compression at this point */
-                       out->dst->flags &= ~MODULE_FLAG_COMPRESS;
-
                        out->dst->flags |= MODULE_FLAG_TYPE_ASL_DIR;
 
                        /* set style bits for basestamp asl_dirs */
                        out->dst->flags |= MODULE_FLAG_TYPE_ASL_DIR;
 
                        /* set style bits for basestamp asl_dirs */
-                       if (((out->dst->flags & MODULE_FLAG_STYLE_BITS) == 0) && (out->dst->flags & MODULE_FLAG_BASESTAMP)) out->dst->flags |= MODULE_FLAG_STYLE_LCL_B;
+                       if (((out->dst->style_flags & MODULE_NAME_STYLE_STAMP_MASK) == 0) && (out->dst->flags & MODULE_FLAG_BASESTAMP)) out->dst->style_flags |= MODULE_NAME_STYLE_STAMP_LCL_B;
                }
 
                /* only ACTION_FILE and ACTION_ASL_FILE may rotate */
                }
 
                /* only ACTION_FILE and ACTION_ASL_FILE may rotate */
@@ -1703,7 +1897,7 @@ asl_out_module_parse_line(asl_out_module_t *m, char *s)
        {
                return _asl_out_module_parse_set_param(m, s);
        }
        {
                return _asl_out_module_parse_set_param(m, s);
        }
-       else if (*s == '>') 
+       else if (*s == '>')
        {
                _asl_out_module_parse_dst(m, s + 1, 010000);
        }
        {
                _asl_out_module_parse_dst(m, s + 1, 010000);
        }
@@ -1742,7 +1936,7 @@ _asl_out_module_find(asl_out_module_t *list, const char *name)
 
        for (x = list; x != NULL; x = x->next)
        {
 
        for (x = list; x != NULL; x = x->next)
        {
-               if ((x->name != NULL) && (!strcmp(x->name, name))) return x;
+               if ((x->name != NULL) && (streq(x->name, name))) return x;
        }
 
        return NULL;
        }
 
        return NULL;
@@ -1770,7 +1964,7 @@ _asl_out_module_read_and_merge_dir(asl_out_module_t **list, const char *path, ui
        {
                while (NULL != (ent = readdir(d)))
                {
        {
                while (NULL != (ent = readdir(d)))
                {
-                       if ((ent->d_name != NULL) && (ent->d_name[0] != '.'))
+                       if (ent->d_name[0] != '.')
                        {
                                /* merge: skip this file if we already have a module with this name */
                                if (_asl_out_module_find(*list, ent->d_name) != NULL) continue;
                        {
                                /* merge: skip this file if we already have a module with this name */
                                if (_asl_out_module_find(*list, ent->d_name) != NULL) continue;
@@ -1787,7 +1981,7 @@ _asl_out_module_read_and_merge_dir(asl_out_module_t **list, const char *path, ui
                                        {
                                                x->flags |= flags;
 
                                        {
                                                x->flags |= flags;
 
-                                               if (!strcmp(ent->d_name, ASL_MODULE_NAME))
+                                               if (streq(ent->d_name, ASL_MODULE_NAME))
                                                {
                                                        /* com.apple.asl goes at the head of the list */
                                                        x->next = *list;
                                                {
                                                        /* com.apple.asl goes at the head of the list */
                                                        x->next = *list;
@@ -1823,10 +2017,10 @@ asl_out_module_init(void)
        char *asl_conf, *asl_conf_dir, *asl_conf_local_dir;
 
        sim_root_path = getenv("IPHONE_SIMULATOR_ROOT");
        char *asl_conf, *asl_conf_dir, *asl_conf_local_dir;
 
        sim_root_path = getenv("IPHONE_SIMULATOR_ROOT");
-       assert(sim_root_path);
+       if (sim_root_path == NULL) return NULL;
 
        sim_resources_path = getenv("IPHONE_SHARED_RESOURCES_DIRECTORY");
 
        sim_resources_path = getenv("IPHONE_SHARED_RESOURCES_DIRECTORY");
-       assert(sim_resources_path);
+       if (sim_resources_path == NULL) return NULL;
 
        asprintf(&asl_conf, "%s%s", sim_root_path, _PATH_ASL_CONF);
        asprintf(&asl_conf_dir, "%s%s", sim_root_path, _PATH_ASL_CONF_DIR);
 
        asprintf(&asl_conf, "%s%s", sim_root_path, _PATH_ASL_CONF);
        asprintf(&asl_conf_dir, "%s%s", sim_root_path, _PATH_ASL_CONF_DIR);
@@ -1885,15 +2079,27 @@ asl_out_module_rule_to_string(asl_out_rule_t *r)
 
        asprintf(&out, "  %s%s%s%s%s",
                         asl_out_action_name[r->action],
 
        asprintf(&out, "  %s%s%s%s%s",
                         asl_out_action_name[r->action],
-                        (r->query == NULL) ? "" : " ", 
+                        (r->query == NULL) ? "" : " ",
                         (r->query == NULL) ? "" : str,
                         (r->query == NULL) ? "" : str,
-                        (r->options == NULL) ? "" : " ", 
+                        (r->options == NULL) ? "" : " ",
                         (r->options == NULL) ? "" : r->options);
 
        free(str);
        return out;
 }
 
                         (r->options == NULL) ? "" : r->options);
 
        free(str);
        return out;
 }
 
+static const char *
+_stamp_style_name(uint32_t flags)
+{
+       if (flags & MODULE_NAME_STYLE_STAMP_SEC) return "<seconds>";
+       if (flags & MODULE_NAME_STYLE_STAMP_SEQ) return "<sequence>";
+       if (flags & MODULE_NAME_STYLE_STAMP_UTC) return "<utc>";
+       if (flags & MODULE_NAME_STYLE_STAMP_UTC_B) return "<utc-basic>";
+       if (flags & MODULE_NAME_STYLE_STAMP_LCL) return "<local>";
+       if (flags & MODULE_NAME_STYLE_STAMP_LCL_B) return "<local-basic>";
+       return "<unknown>";
+}
+
 /*
  * Print module
  */
 /*
  * Print module
  */
@@ -1903,6 +2109,7 @@ asl_out_module_print(FILE *f, asl_out_module_t *m)
        asl_out_rule_t *r, *n;
        asl_out_dst_data_t *o;
        uint32_t i, ttlnset;
        asl_out_rule_t *r, *n;
        asl_out_dst_data_t *o;
        uint32_t i, ttlnset;
+       char tstr[150];
 
        n = NULL;
        for (r = m->ruleset; r != NULL; r = n)
 
        n = NULL;
        for (r = m->ruleset; r != NULL; r = n)
@@ -1957,39 +2164,14 @@ asl_out_module_print(FILE *f, asl_out_module_t *m)
                                                fprintf(f, "%ccompress", c);
                                                c = ' ';
                                        }
                                                fprintf(f, "%ccompress", c);
                                                c = ' ';
                                        }
-                                       if (o->flags & MODULE_FLAG_STYLE_SEC)
-                                       {
-                                               fprintf(f, "%cseconds", c);
-                                               c = ' ';
-                                       }
-                                       if (o->flags & MODULE_FLAG_STYLE_SEQ)
-                                       {
-                                               fprintf(f, "%csequence", c);
-                                               c = ' ';
-                                       }
-                                       if (o->flags & MODULE_FLAG_STYLE_UTC)
-                                       {
-                                               fprintf(f, "%cutc", c);
-                                               c = ' ';
-                                       }
-                                       if (o->flags & MODULE_FLAG_STYLE_UTC_B)
-                                       {
-                                               fprintf(f, "%cutc-basic", c);
-                                               c = ' ';
-                                       }
-                                       if (o->flags & MODULE_FLAG_STYLE_LCL)
-                                       {
-                                               fprintf(f, "%clocal", c);
-                                               c = ' ';
-                                       }
-                                       if (o->flags & MODULE_FLAG_STYLE_LCL_B)
+                                       if (o->flags & MODULE_FLAG_BASESTAMP)
                                        {
                                        {
-                                               fprintf(f, "%clocal-basic", c);
+                                               fprintf(f, "%cbasestamp", c);
                                                c = ' ';
                                        }
                                                c = ' ';
                                        }
-                                       if (o->flags & MODULE_FLAG_BASESTAMP)
+                                       if (o->flags & MODULE_FLAG_SYMLINK)
                                        {
                                        {
-                                               fprintf(f, "%cbasestamp", c);
+                                               fprintf(f, "%csymlink", c);
                                                c = ' ';
                                        }
                                        if (o->flags & MODULE_FLAG_NONSTD_DIR)
                                                c = ' ';
                                        }
                                        if (o->flags & MODULE_FLAG_NONSTD_DIR)
@@ -2002,6 +2184,11 @@ asl_out_module_print(FILE *f, asl_out_module_t *m)
                                                fprintf(f, "%cexternal", c);
                                                c = ' ';
                                        }
                                                fprintf(f, "%cexternal", c);
                                                c = ' ';
                                        }
+                                       if (o->flags & MODULE_FLAG_ACTIVITY)
+                                       {
+                                               fprintf(f, "%cactivity", c);
+                                               c = ' ';
+                                       }
                                        if (o->flags & MODULE_FLAG_CRASHLOG)
                                        {
                                                fprintf(f, "%ccrashlog", c);
                                        if (o->flags & MODULE_FLAG_CRASHLOG)
                                        {
                                                fprintf(f, "%ccrashlog", c);
@@ -2021,11 +2208,45 @@ asl_out_module_print(FILE *f, asl_out_module_t *m)
                                }
                                fprintf(f, "\n");
 
                                }
                                fprintf(f, "\n");
 
-                               fprintf(f, "    ttl: %u", o->ttl[LEVEL_ALL]);
+                               if (o->flags & MODULE_FLAG_ROTATE)
+                               {
+                                       fprintf(f, "        rotatation style: ");
+                                       if (o->style_flags & MODULE_NAME_STYLE_FORMAT_BS)
+                                       {
+                                               fprintf(f, "[base=%s].%s\n", o->base, _stamp_style_name(o->style_flags));
+                                       }
+                                       else if (o->style_flags & MODULE_NAME_STYLE_FORMAT_BES)
+                                       {
+                                               fprintf(f, "[base=%s].[ext=%s].%s\n", o->base, o->ext, _stamp_style_name(o->style_flags));
+                                       }
+                                       else if (o->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)
+                                       {
+                                               fprintf(f, "[base=%s].%s.[ext=%s]\n", o->base, _stamp_style_name(o->style_flags), o->ext);
+                                       }
+                                       else
+                                       {
+                                               fprintf(f, "0x%08x\n", o->style_flags);
+                                       }
+                               }
+
+                               asl_core_time_to_str(o->ttl[LEVEL_ALL], tstr, sizeof(tstr));
+                               fprintf(f, "    ttl: %s\n", tstr);
+
                                ttlnset = 0;
                                for (i = 0; (i <= 7) & (ttlnset == 0); i++) if (o->ttl[i] != 0) ttlnset = 1;
                                ttlnset = 0;
                                for (i = 0; (i <= 7) & (ttlnset == 0); i++) if (o->ttl[i] != 0) ttlnset = 1;
-                               if (ttlnset != 0) for (i = 0; i <= 7; i++) printf(" [%d %d]", i, (o->ttl[i] == 0) ? o->ttl[LEVEL_ALL] : o->ttl[i]);
-                               fprintf(f, "\n");
+                               if (ttlnset != 0)
+                               {
+                                       for (i = 0; i <= 7; i++)
+                                       {
+                                               time_t x = o->ttl[i];
+                                               if (x == 0) x = o->ttl[LEVEL_ALL];
+                                               asl_core_time_to_str(x, tstr, sizeof(tstr));
+
+                                               fprintf(f, " [%d %s]", i, tstr);
+                                       }
+
+                                       fprintf(f, "\n");
+                               }
 
                                fprintf(f, "    mode: 0%o\n", o->mode);
                                fprintf(f, "    file_max: %lu\n", o->file_max);
 
                                fprintf(f, "    mode: 0%o\n", o->mode);
                                fprintf(f, "    file_max: %lu\n", o->file_max);
@@ -2064,100 +2285,262 @@ asl_out_file_list_free(asl_out_file_list_t *l)
 }
 
 /*
 }
 
 /*
- * Checks input name for the form base[.stamp][.gz]
- * name == base is allowed if src is true.
+ * Checks input name for one of the forms:
+ * MODULE_NAME_STYLE_FORMAT_BS base (src only) or base.stamp[.gz]
+ * MODULE_NAME_STYLE_FORMAT_BES base.ext (src only) or base.ext.stamp[.gz]
+ * MODULE_NAME_STYLE_FORMAT_BSE base.ext (src only) or base.stamp.ext[.gz]
+ *
+ * name == base[.ext] is allowed if src is true.
  * base.gz is not allowed.
  * Output parameter stamp must be freed by caller.
  */
 bool
  * base.gz is not allowed.
  * Output parameter stamp must be freed by caller.
  */
 bool
-_check_file_name(const char *name, const char *base, bool src, char **stamp)
+_check_file_name(const char *name, const char *base, const char *ext, uint32_t flags, bool src, char **stamp)
 {
 {
-       size_t baselen, nparts;
-       const char *p, *q, *part[2];
+       size_t baselen, extlen;
+       const char *p, *z;
        bool isgz = false;
 
        bool isgz = false;
 
+#ifdef DEBUG_LIST_FILES
+       fprintf(stderr, "_check_file_name name=%s base=%s ext=%s flags=0x%08x %s\n", name, base, (ext == NULL) ? "(NULL)" : ext, flags, src ? "src" : "dst");
+#endif
+
        if (name == NULL) return false;
        if (base == NULL) return false;
 
        baselen = strlen(base);
        if (baselen == 0) return false;
 
        if (name == NULL) return false;
        if (base == NULL) return false;
 
        baselen = strlen(base);
        if (baselen == 0) return false;
 
+       extlen = 0;
+       if (ext != NULL) extlen = strlen(ext);
+
        if (stamp != NULL) *stamp = NULL;
 
        if (stamp != NULL) *stamp = NULL;
 
-       if (strncmp(name, base, baselen)) return false;
+       if (strneq_len(name, base, baselen))
+       {
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "  base match failed [%u]\n", __LINE__);
+#endif
+               return false;
+       }
 
 
-       p = name + baselen;
+       z = strrchr(name, '.');
+       if ((z != NULL) && streq(z, ".gz")) isgz = true;
 
 
-       /* name == base not allowed (it's the "active" file) */
-       if (*p == '\0') return false;
+#ifdef DEBUG_LIST_FILES
+       fprintf(stderr, "z=%s isgz=%s\n", (z == NULL) ? "NULL" : z, isgz ? "true" : "false");
+#endif
 
 
-       /* name must be base.something */
-       if (*p != '.') return false;
+       p = name + baselen;
 
 
-       /* maximum of 2 parts (stamp and gz) */
-       nparts = 0;
-       for (q = p; *q != '\0'; q++)
+       if (flags & MODULE_NAME_STYLE_FORMAT_BS)
        {
        {
-               if (*q == '.')
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "  MODULE_NAME_STYLE_FORMAT_BS\n");
+#endif
+               if (*p == '\0')
                {
                {
-                       if (nparts == 2) return false;
-                       part[nparts++] = q + 1;
+                       /* name == base OK if src is true */
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "  name == base %s [%u]\n", src ? "OK" : "failed", __LINE__);
+#endif
+                       return src;
                }
                }
-       }
 
 
-       if (nparts == 0) return false;
+               /* expecting p == .stamp[.gz] */
+               if (*p != '.')
+               {
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "  expecting dot - failed [%u]\n", __LINE__);
+#endif
+                       return false;
+               }
 
 
-       isgz = strcmp(part[nparts - 1], "gz") == 0;
+               p++;
 
 
-       /* no compressed files in src */
-       if (src && isgz) return false;
+               if (p == z)
+               {
+                       /* base.gz is not allowed */
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "  got base.gz - failed [%u]\n", __LINE__);
+#endif
+                       return false;
+               }
 
 
-       /* expecting base.stamp or base.stamp.gz */
+               /* got base.stamp[.gz] */
+               if (stamp != NULL)
+               {
+                       *stamp = strdup(p);
+                       char *x = strchr(*stamp, '.');
+                       if (x != NULL) *x = '\0';
+               }
 
 
-       if (nparts == 1)
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "  got base.stamp%s - OK\n", isgz ? ".gz" : "");
+#endif
+               return true;
+       }
+       else if (flags & MODULE_NAME_STYLE_FORMAT_BES)
        {
        {
-               /* compressed files must have a stamp (base.gz is not allowed) */
-               if (isgz) return false;
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "  MODULE_NAME_STYLE_FORMAT_BES\n");
+#endif
+               if (*p != '.')
+               {
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "  expecting dot - failed [%u]\n", __LINE__);
+#endif
+                       return false;
+               }
+
+               p++;
+
+               if (strneq_len(p, ext, extlen))
+               {
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "  ext match failed [%u]\n", __LINE__);
+#endif
+                       return false;
+               }
 
 
-               /* got base.stamp */
-               if (stamp != NULL) *stamp = strdup(part[0]);
+               /* expecting p == .ext[.stamp][.gz] */
+               p += extlen;
+
+               if (*p == '\0')
+               {
+                       /* name == base.ext OK if src is true */
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "  name == base.ext %s [%u]\n", src ? "OK" : "failed", __LINE__);
+#endif
+                       return src;
+               }
+
+               /* expecting p == .stamp[.gz] */
+               if (*p != '.')
+               {
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "  expecting dot - failed [%u]\n", __LINE__);
+#endif
+                       return false;
+               }
+
+               p++;
+
+               if (p == z)
+               {
+                       /* base.ext.gz is not allowed */
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "  got base.ext.gz - failed [%u]\n", __LINE__);
+#endif
+                       return false;
+               }
+
+               /* got base.ext.stamp[.gz] */
+               if (stamp != NULL)
+               {
+                       *stamp = strdup(p);
+                       char *x = strchr(*stamp, '.');
+                       if (x != NULL) *x = '\0';
+               }
+
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "  got base.ext.stamp%s - OK\n", isgz ? ".gz" : "");
+#endif
                return true;
        }
                return true;
        }
+       else if (flags & MODULE_NAME_STYLE_FORMAT_BSE)
+       {
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "  MODULE_NAME_STYLE_FORMAT_BSE name=%s base=%s ext=%s flags=0x%08x %s\n", name, base, (ext == NULL) ? "(NULL)" : ext, flags, src ? "src" : "dst");
+#endif
 
 
-       /* expecting base.stamp.gz */
-       if (!isgz) return false;
+               if (*p != '.')
+               {
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "  expecting dot - failed [%u]\n", __LINE__);
+#endif
+                       return false;
+               }
 
 
-       /* got base.stamp.gz */
-       if (stamp != NULL)
-       {
-               *stamp = strdup(part[0]);
-               char *x = strchr(*stamp, '.');
-               if (x != NULL) *x = '\0';
+               p++;
+
+               if (streq_len(p, ext, extlen))
+               {
+                       p += extlen;
+                       if (*p == '\0')
+                       {
+                               /* name == base.ext OK if src is true */
+#ifdef DEBUG_LIST_FILES
+                               fprintf(stderr, "  name == base.ext %s [%u]\n", src ? "OK" : "failed", __LINE__);
+#endif
+                               return src;
+                       }
+               }
+
+               /* expecting p == stamp.ext[.gz] */
+
+               if (isgz)
+               {
+                       if (strneq_len(z - extlen, ext, extlen))
+                       {
+#ifdef DEBUG_LIST_FILES
+                               fprintf(stderr, "  ext match (%s) isgz failed [%u]\n", z-extlen, __LINE__);
+#endif
+                               return false;
+                       }
+               }
+               else
+               {
+                       if (strneq_len(z + 1, ext, extlen))
+                       {
+#ifdef DEBUG_LIST_FILES
+                               fprintf(stderr, "  ext match (%s) failed [%u]\n", z, __LINE__);
+#endif
+                               return false;
+                       }
+               }
+
+               /* got base.stamp.ext[.gz] */
+               if (stamp != NULL)
+               {
+                       *stamp = strdup(p);
+                       char *x = strchr(*stamp, '.');
+                       if (x != NULL) *x = '\0';
+               }
+
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "  got base.stamp.ext%s - OK\n", isgz ? ".gz" : "");
+#endif
+               return true;
        }
 
        }
 
-       return true;
+#ifdef DEBUG_LIST_FILES
+       fprintf(stderr, "  unknown format - failed\n");
+#endif
+
+       return false;
 }
 
 /*
  * Find files in a directory (dir) that all have a common prefix (base).
  * Bits in flags further control the search.
  *
 }
 
 /*
  * Find files in a directory (dir) that all have a common prefix (base).
  * Bits in flags further control the search.
  *
- * MODULE_FLAG_STYLE_SEQ means a numeric sequence number is expected, although not required.
+ * MODULE_NAME_STYLE_STAMP_SEQ means a numeric sequence number is expected, although not required.
  * E.g. foo.log foo.log.0
  *
  * E.g. foo.log foo.log.0
  *
- * MODULE_FLAG_STYLE_SEC also means a numeric sequence number is required following an 'T' character.
+ * MODULE_NAME_STYLE_STAMP_SEC also means a numeric sequence number is required following an 'T' character.
  * The numeric value is the file's timestamp in seconds.  E.g foo.log.T1335200452
  *
  * The numeric value is the file's timestamp in seconds.  E.g foo.log.T1335200452
  *
- * MODULE_FLAG_STYLE_UTC requires a date/time component as the file's timestamp.
+ * MODULE_NAME_STYLE_STAMP_UTC requires a date/time component as the file's timestamp.
  * E.g. foo.2012-04-06T15:30:00Z
  *
  * E.g. foo.2012-04-06T15:30:00Z
  *
- * MODULE_FLAG_STYLE_UTC_B requires a date/time component as the file's timestamp.
+ * MODULE_NAME_STYLE_STAMP_UTC_B requires a date/time component as the file's timestamp.
  * E.g. foo.20120406T153000Z
  *
  * E.g. foo.20120406T153000Z
  *
- * MODULE_FLAG_STYLE_LCL requires a date/time component as the file's timestamp.
+ * MODULE_NAME_STYLE_STAMP_LCL requires a date/time component as the file's timestamp.
  * E.g. foo.2012-04-06T15:30:00-7
  *
  * E.g. foo.2012-04-06T15:30:00-7
  *
- * MODULE_FLAG_STYLE_LCL_B requires a date/time component as the file's timestamp.
+ * MODULE_NAME_STYLE_STAMP_LCL_B requires a date/time component as the file's timestamp.
  * E.g. foo.20120406T153000-07
  */
 int
  * E.g. foo.20120406T153000-07
  */
 int
@@ -2174,7 +2557,7 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp)
        /* check for NULL (no stamp) */
        if (stamp == NULL) return STAMP_STYLE_NULL;
 
        /* check for NULL (no stamp) */
        if (stamp == NULL) return STAMP_STYLE_NULL;
 
-       /* check for MODULE_FLAG_STYLE_SEC (foo.T12345678) */
+       /* check for MODULE_NAME_STYLE_STAMP_SEC (foo.T12345678) */
        if (stamp[0] == 'T')
        {
                n = atoi(stamp + 1);
        if (stamp[0] == 'T')
        {
                n = atoi(stamp + 1);
@@ -2184,11 +2567,11 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp)
                return STAMP_STYLE_SEC;
        }
 
                return STAMP_STYLE_SEC;
        }
 
-       /* check for MODULE_FLAG_STYLE_SEQ (foo.0 or foo.2.gz) */
+       /* check for MODULE_NAME_STYLE_STAMP_SEQ (foo.0 or foo.2.gz) */
        digits = true;
        for (i = 0; digits && (stamp[i] != '\0'); i++) digits = (stamp[i] >= '0') && (stamp[i] <= '9');
 
        digits = true;
        for (i = 0; digits && (stamp[i] != '\0'); i++) digits = (stamp[i] >= '0') && (stamp[i] <= '9');
 
-       if (!digits && (!strcmp(stamp + i, ".gz"))) digits = true;
+       if (!digits && (streq(stamp + i, ".gz"))) digits = true;
 
        if (digits)
        {
 
        if (digits)
        {
@@ -2197,25 +2580,34 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp)
                return STAMP_STYLE_SEQ;
        }
 
                return STAMP_STYLE_SEQ;
        }
 
-       /* check for MODULE_FLAG_STYLE_UTC, UTC_B, LCL, or LCL_B */
+       /* check for MODULE_NAME_STYLE_STAMP_UTC, UTC_B, LCL, or LCL_B */
        memset(&t, 0, sizeof(t));
        h = m = s = 0;
 
        n = 0;
        memset(&t, 0, sizeof(t));
        h = m = s = 0;
 
        n = 0;
-       if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_LCL))
+       if ((flags & MODULE_NAME_STYLE_STAMP_UTC) || (flags & MODULE_NAME_STYLE_STAMP_LCL))
        {
                n = sscanf(stamp, "%d-%d-%dT%d:%d:%d%c%u:%u:%u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s);
        }
        {
                n = sscanf(stamp, "%d-%d-%dT%d:%d:%d%c%u:%u:%u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s);
        }
-       else if ((flags & MODULE_FLAG_STYLE_UTC_B) || (flags & MODULE_FLAG_STYLE_LCL_B))
+       else if ((flags & MODULE_NAME_STYLE_STAMP_UTC_B) || (flags & MODULE_NAME_STYLE_STAMP_LCL_B))
        {
                n = sscanf(stamp, "%4d%2d%2dT%2d%2d%2d%c%2u%2u%2u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s);
        }
        else
        {
        {
                n = sscanf(stamp, "%4d%2d%2dT%2d%2d%2d%c%2u%2u%2u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s);
        }
        else
        {
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "_parse_stamp_style fail %u\n", __LINE__);
+#endif
                return STAMP_STYLE_INVALID;
        }
 
                return STAMP_STYLE_INVALID;
        }
 
-       if (n < 6) return STAMP_STYLE_INVALID;
+       if (n < 6)
+       {
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "_parse_stamp_style fail %u\n", __LINE__);
+#endif
+               return STAMP_STYLE_INVALID;
+       }
 
        if (n == 6)
        {
 
        if (n == 6)
        {
@@ -2226,7 +2618,7 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp)
                if (n >= 8) utc_offset += (3600 * h);
                if (n >= 9) utc_offset += (60 * m);
                if (n == 10) utc_offset += s;
                if (n >= 8) utc_offset += (3600 * h);
                if (n >= 9) utc_offset += (60 * m);
                if (n == 10) utc_offset += s;
-               if (zone == '-') utc_offset *= -1;
+               if (zone == '+') utc_offset *= -1;
        }
        else if ((zone >= 'A') && (zone <= 'Z'))
        {
        }
        else if ((zone >= 'A') && (zone <= 'Z'))
        {
@@ -2242,6 +2634,9 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp)
        }
        else
        {
        }
        else
        {
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "_parse_stamp_style fail %u\n", __LINE__);
+#endif
                return STAMP_STYLE_INVALID;
        }
 
                return STAMP_STYLE_INVALID;
        }
 
@@ -2255,11 +2650,11 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp)
 
        if (tp != NULL) *tp = ftime;
 
 
        if (tp != NULL) *tp = ftime;
 
-       return STAMP_STYLE_UTC_OR_LCL;
+       return STAMP_STYLE_ISO8601;
 }
 
 asl_out_file_list_t *
 }
 
 asl_out_file_list_t *
-asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
+asl_list_log_files(const char *dir, const char *base, const char *ext, uint32_t flags, bool src)
 {
        DIR *d;
        struct dirent *ent;
 {
        DIR *d;
        struct dirent *ent;
@@ -2270,6 +2665,10 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
        int pstyle, fstyle;
        asl_out_file_list_t *out, *x, *y;
 
        int pstyle, fstyle;
        asl_out_file_list_t *out, *x, *y;
 
+#ifdef DEBUG_LIST_FILES
+       fprintf(stderr, "asl_list_log_files dir=%s base=%s ext=%s flags=0x%08x %s\n", dir, base, (ext == NULL) ? "(NULL)" : ext, flags, src ? "src" : "dst");
+#endif
+
        if (dir == NULL) return NULL;
        if (base == NULL) return NULL;
 
        if (dir == NULL) return NULL;
        if (base == NULL) return NULL;
 
@@ -2282,10 +2681,9 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
        {
                char *stamp = NULL;
                bool check;
        {
                char *stamp = NULL;
                bool check;
+               bool stat_ok = false;
 
 
-               if (ent->d_name == NULL) continue;
-
-               check = _check_file_name(ent->d_name, base, src, &stamp);
+               check = _check_file_name(ent->d_name, base, ext, flags, src, &stamp);
                if (!check) continue;
 
                seq = IndexNull;
                if (!check) continue;
 
                seq = IndexNull;
@@ -2296,11 +2694,24 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
 
                if (pstyle == STAMP_STYLE_INVALID) continue;
 
 
                if (pstyle == STAMP_STYLE_INVALID) continue;
 
+               snprintf(path, sizeof(path), "%s/%s", dir, ent->d_name);
+               memset(&sb, 0, sizeof(sb));
+               if (lstat(path, &sb) == 0)
+               {
+                       /* ignore symlinks (created for basestamp / symlink files) */
+                       stat_ok = true;
+                       if ((sb.st_mode & S_IFMT) == S_IFLNK) continue;
+               }
+
                fstyle = STAMP_STYLE_NULL;
                fstyle = STAMP_STYLE_NULL;
-               if (flags & MODULE_FLAG_STYLE_SEC) fstyle = STAMP_STYLE_SEC;
-               else if (flags & MODULE_FLAG_STYLE_SEQ) fstyle = STAMP_STYLE_SEQ;
-               else if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_LCL)) fstyle = STAMP_STYLE_UTC_OR_LCL;
-               else if ((flags & MODULE_FLAG_STYLE_UTC_B) || (flags & MODULE_FLAG_STYLE_LCL_B)) fstyle = STAMP_STYLE_UTC_OR_LCL;
+               if (flags & MODULE_NAME_STYLE_STAMP_SEC) fstyle = STAMP_STYLE_SEC;
+               else if (flags & MODULE_NAME_STYLE_STAMP_SEQ) fstyle = STAMP_STYLE_SEQ;
+               else if ((flags & MODULE_NAME_STYLE_STAMP_UTC) || (flags & MODULE_NAME_STYLE_STAMP_LCL)) fstyle = STAMP_STYLE_ISO8601;
+               else if ((flags & MODULE_NAME_STYLE_STAMP_UTC_B) || (flags & MODULE_NAME_STYLE_STAMP_LCL_B)) fstyle = STAMP_STYLE_ISO8601;
+
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "%s %s %u fstyle %u pstyle %u\n", __func__, path, __LINE__, fstyle, pstyle);
+#endif
 
                /*
                 * accept the file if:
 
                /*
                 * accept the file if:
@@ -2314,8 +2725,14 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
                if ((pstyle == STAMP_STYLE_SEC) && src) check = true;
                if (pstyle == fstyle) check = true;
 
                if ((pstyle == STAMP_STYLE_SEC) && src) check = true;
                if (pstyle == fstyle) check = true;
 
-               if (!check) continue;
-
+               if (!check)
+               {
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "%s reject %s at line %u\n", __func__, path, __LINE__);
+#endif
+                       continue;
+               }
+       
                x = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t));
                if (x == NULL)
                {
                x = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t));
                if (x == NULL)
                {
@@ -2324,12 +2741,11 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
                }
 
                x->name = strdup(ent->d_name);
                }
 
                x->name = strdup(ent->d_name);
+               x->stamp = pstyle;
                x->ftime = ftime;
                x->seq = seq;
 
                x->ftime = ftime;
                x->seq = seq;
 
-               memset(&sb, 0, sizeof(sb));
-               snprintf(path, sizeof(path), "%s/%s", dir, ent->d_name);
-               if (stat(path, &sb) == 0)
+               if (stat_ok)
                {
                        x->size = sb.st_size;
                        if (pstyle == STAMP_STYLE_SEQ)
                {
                        x->size = sb.st_size;
                        if (pstyle == STAMP_STYLE_SEQ)
@@ -2341,11 +2757,14 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
 
                if (pstyle == STAMP_STYLE_SEQ)
                {
 
                if (pstyle == STAMP_STYLE_SEQ)
                {
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "asl_list_log_files SEQ  %s %u %ld\n", path, x->seq, x->ftime);
+#endif
                        if (out == NULL)
                        {
                                out = x;
                        }
                        if (out == NULL)
                        {
                                out = x;
                        }
-                       else if ((x->seq == IndexNull) || ((x->seq < out->seq) && (out->seq != IndexNull)))
+                       else if ((x->seq == IndexNull) || ((x->seq > out->seq) && (out->seq != IndexNull)))
                        {
                                x->next = out;
                                out->prev = x;
                        {
                                x->next = out;
                                out->prev = x;
@@ -2361,7 +2780,7 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
                                                x->prev = y;
                                                break;
                                        }
                                                x->prev = y;
                                                break;
                                        }
-                                       else if ((x->seq < y->next->seq) && (y->next->seq != IndexNull))
+                                       else if ((x->seq > y->next->seq) && (y->next->seq != IndexNull))
                                        {
                                                x->next = y->next;
                                                y->next = x;
                                        {
                                                x->next = y->next;
                                                y->next = x;
@@ -2374,6 +2793,9 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
                }
                else
                {
                }
                else
                {
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "asl_list_log_files TIME %s %ld\n", path, x->ftime);
+#endif
                        if (out == NULL)
                        {
                                out = x;
                        if (out == NULL)
                        {
                                out = x;
@@ -2417,12 +2839,14 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
 asl_out_file_list_t *
 asl_list_src_files(asl_out_dst_data_t *dst)
 {
 asl_out_file_list_t *
 asl_list_src_files(asl_out_dst_data_t *dst)
 {
-       char *base;
-       uint32_t flags = MODULE_FLAG_STYLE_SEC;
-       asl_out_file_list_t *out;
+       uint32_t flags;
+#ifdef DEBUG_LIST_FILES
+       fprintf(stderr, "asl_list_src_files\n");
+#endif
 
        if (dst == NULL) return NULL;
        if (dst->path == NULL) return NULL;
 
        if (dst == NULL) return NULL;
        if (dst->path == NULL) return NULL;
+       if (dst->base == NULL) return NULL;
 
        /*
         * MODULE_FLAG_EXTERNAL means some process other than syslogd writes the file.
 
        /*
         * MODULE_FLAG_EXTERNAL means some process other than syslogd writes the file.
@@ -2438,7 +2862,7 @@ asl_list_src_files(asl_out_dst_data_t *dst)
                {
                        if (S_ISREG(sb.st_mode) && (sb.st_size != 0))
                        {
                {
                        if (S_ISREG(sb.st_mode) && (sb.st_size != 0))
                        {
-                               out = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t));
+                               asl_out_file_list_t *out = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t));
                                if (out != NULL)
                                {
                                        char *p = strrchr(dst->path, '/');
                                if (out != NULL)
                                {
                                        char *p = strrchr(dst->path, '/');
@@ -2455,40 +2879,24 @@ asl_list_src_files(asl_out_dst_data_t *dst)
                return NULL;
        }
 
                return NULL;
        }
 
-       /*
-        * Checkpoint / source format may be one of:
-        * MODULE_FLAG_STYLE_SEC   (foo.T12345678.log),
-        * MODULE_FLAG_STYLE_UTC   (foo.20120-06-24T12:34:56Z.log)
-        * MODULE_FLAG_STYLE_UTC_B (foo.201200624T123456Z.log)
-        * MODULE_FLAG_STYLE_LCL   (foo.20120-06-24T12:34:56-7.log)
-        * MODULE_FLAG_STYLE_LCL_B (foo.201200624T123456-07.log)
-        *
-        * MODULE_FLAG_STYLE_SEC format is used for sequenced (MODULE_FLAG_STYLE_SEQ) files.
-        * aslmanager converts the file names.
-        */
-
-       if (dst->flags & MODULE_FLAG_STYLE_UTC) flags = MODULE_FLAG_STYLE_UTC;
-       else if (dst->flags & MODULE_FLAG_STYLE_UTC_B) flags = MODULE_FLAG_STYLE_UTC_B;
-       else if (dst->flags & MODULE_FLAG_STYLE_LCL) flags = MODULE_FLAG_STYLE_LCL;
-       else if (dst->flags & MODULE_FLAG_STYLE_LCL_B) flags = MODULE_FLAG_STYLE_LCL_B;
-
-       if ((dst->rotate_dir == NULL) && ((dst->flags & MODULE_FLAG_STYLE_SEQ) == 0) && ((dst->flags & MODULE_FLAG_COMPRESS) == 0))
+       if ((dst->rotate_dir == NULL) && (dst->flags & MODULE_FLAG_BASESTAMP) && ((dst->flags & MODULE_FLAG_COMPRESS) == 0))
        {
                /* files do not move to a dest dir, get renamed, or get compressed - nothing to do */
                return NULL;
        }
 
        {
                /* files do not move to a dest dir, get renamed, or get compressed - nothing to do */
                return NULL;
        }
 
-       base = strrchr(dst->path, '/');
-       if (base == NULL) return NULL;
-
-       *base = '\0';
-       base++;
-
-       out = asl_list_log_files(dst->path, base, true, flags);
-
-       if (base != NULL) *--base = '/';
+       /*
+        * MODULE_NAME_STYLE_STAMP_SEC format is used for sequenced (MODULE_NAME_STYLE_STAMP_SEQ) files.
+        * aslmanager converts the file names.
+        */
+       flags = dst->style_flags;
+       if (flags & MODULE_NAME_STYLE_STAMP_SEQ)
+       {
+               flags &= ~MODULE_NAME_STYLE_STAMP_SEQ;
+               flags |= MODULE_NAME_STYLE_STAMP_SEC;
+       }
 
 
-       return out;
+       return asl_list_log_files(dst->dir, dst->base, dst->ext, flags, true);
 }
 
 /*
 }
 
 /*
@@ -2497,26 +2905,19 @@ asl_list_src_files(asl_out_dst_data_t *dst)
 asl_out_file_list_t *
 asl_list_dst_files(asl_out_dst_data_t *dst)
 {
 asl_out_file_list_t *
 asl_list_dst_files(asl_out_dst_data_t *dst)
 {
-       char *base, *dst_dir;
-       asl_out_file_list_t *out;
+       char *dst_dir;
+#ifdef DEBUG_LIST_FILES
+       fprintf(stderr, "asl_list_dst_files\n");
+#endif
 
        if (dst == NULL) return NULL;
        if (dst->path == NULL) return NULL;
 
        if (dst == NULL) return NULL;
        if (dst->path == NULL) return NULL;
-
-       base = strrchr(dst->path, '/');
-       if (base == NULL) return NULL;
-
-       *base = '\0';
-       base++;
+       if (dst->base == NULL) return NULL;
 
        dst_dir = dst->rotate_dir;
 
        dst_dir = dst->rotate_dir;
-       if (dst_dir == NULL) dst_dir = dst->path;
-
-       out = asl_list_log_files(dst_dir, base, false, dst->flags);
-
-       if (base != NULL) *--base = '/';
+       if (dst_dir == NULL) dst_dir = dst->dir;
 
 
-       return out;
+       return asl_list_log_files(dst_dir, dst->base, dst->ext, dst->style_flags, false);
 }
 
 static int
 }
 
 static int
@@ -2576,7 +2977,7 @@ int
 asl_secure_chown_chmod_dir(const char *path, uid_t uid, gid_t gid, mode_t mode)
 {
        int fd, status;
 asl_secure_chown_chmod_dir(const char *path, uid_t uid, gid_t gid, mode_t mode)
 {
        int fd, status;
+
        fd = asl_secure_open_dir(path);
        if (fd < 0) return fd;
 
        fd = asl_secure_open_dir(path);
        if (fd < 0) return fd;
 
index 78028879c3d3d28fd4b0e96e907eb2262f43dcb6..5f923939cd16b4d23a6a3932aac9b4b06f7ebfc3 100644 (file)
@@ -2,14 +2,14 @@
  * Copyright (c) 2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * Copyright (c) 2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -17,7 +17,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
  * @APPLE_LICENSE_HEADER_END@
  */
 
 
 #include <stdio.h>
 #include <xpc/xpc.h>
 
 #include <stdio.h>
 #include <xpc/xpc.h>
+#include <asl_msg.h>
 
 #define ASL_MODULE_NAME "com.apple.asl"
 #define _PATH_CRASHREPORTER "/Library/Logs/CrashReporter"
 
 #define ASL_MODULE_NAME "com.apple.asl"
 #define _PATH_CRASHREPORTER "/Library/Logs/CrashReporter"
-#define _PATH_CRASHREPORTER_MOBILE "/var/mobile/Library/Logs/CrashReporter"
+#define _PATH_CRASHREPORTER_MOBILE_1 "/var/mobile/Library/Logs/CrashReporter"
+#define _PATH_CRASHREPORTER_MOBILE_2 "/private/var/mobile/Library/Logs/CrashReporter"
+#define ASL_INTERNAL_LOGS_DIR "Logs"
 
 #define ASL_SERVICE_NAME "com.apple.system.logger"
 
 #define CRASH_MOVER_WILL_START_NOTIFICATION  "CrashMoverWillStart"
 
 
 #define ASL_SERVICE_NAME "com.apple.system.logger"
 
 #define CRASH_MOVER_WILL_START_NOTIFICATION  "CrashMoverWillStart"
 
-#define DEFAULT_TTL 7 /* days */
 #define SECONDS_PER_DAY 86400
 #define SECONDS_PER_DAY 86400
+#define DEFAULT_TTL (7 * SECONDS_PER_DAY)
 
 #define ACTION_NONE       0
 #define ACTION_SET_PARAM  1
 
 #define ACTION_NONE       0
 #define ACTION_SET_PARAM  1
 #define MODULE_FLAG_NONSTD_DIR   0x00000020
 #define MODULE_FLAG_EXTERNAL     0x00000040
 #define MODULE_FLAG_TRUNCATE     0x00000080
 #define MODULE_FLAG_NONSTD_DIR   0x00000020
 #define MODULE_FLAG_EXTERNAL     0x00000040
 #define MODULE_FLAG_TRUNCATE     0x00000080
-#define MODULE_FLAG_STYLE_SEC    0x00000100 /* foo.T1332799722 (note STYLE_SEC_PREFIX_CHAR) */
-#define MODULE_FLAG_STYLE_SEQ    0x00000200 /* foo.0 */
-#define MODULE_FLAG_STYLE_UTC    0x00000400 /* foo.2012-04-06T13:45:00Z */
-#define MODULE_FLAG_STYLE_UTC_B  0x00000800 /* ("basic utc") foo.20120406T134500Z */
-#define MODULE_FLAG_STYLE_LCL    0x00001000 /* foo.2012-04-06T13:45:00-7 */
-#define MODULE_FLAG_STYLE_LCL_B  0x00002000 /* ("basic local") foo.20120406T134500-7 */
-#define MODULE_FLAG_BASESTAMP    0x00004000 /* base file has timestamp */
-#define MODULE_FLAG_CRASHLOG     0x00008000 /* checkpoint on CrashMoverWillStart notification */
-#define MODULE_FLAG_SOFT_WRITE   0x00010000 /* ignore write failures */
-#define MODULE_FLAG_TYPE_ASL     0x00020000 /* asl format file */
-#define MODULE_FLAG_TYPE_ASL_DIR 0x00040000 /* asl format directory */
-#define MODULE_FLAG_STD_BSD_MSG  0x00080000 /* print format is std, bsd, or msg */
-
-#define MODULE_FLAG_STYLE_BITS   (MODULE_FLAG_STYLE_SEC | MODULE_FLAG_STYLE_SEQ | MODULE_FLAG_STYLE_UTC | MODULE_FLAG_STYLE_UTC_B | MODULE_FLAG_STYLE_LCL | MODULE_FLAG_STYLE_LCL_B)
+#define MODULE_FLAG_BASESTAMP    0x00000100 /* base file has timestamp */
+#define MODULE_FLAG_SYMLINK      0x00000200 /* link to basestamp name */
+#define MODULE_FLAG_CRASHLOG     0x00000400 /* checkpoint on CrashMoverWillStart notification */
+#define MODULE_FLAG_SOFT_WRITE   0x00000800 /* ignore write failures */
+#define MODULE_FLAG_TYPE_ASL     0x00001000 /* asl format file */
+#define MODULE_FLAG_TYPE_ASL_DIR 0x00002000 /* asl format directory */
+#define MODULE_FLAG_STD_BSD_MSG  0x00004000 /* print format is std, bsd, or msg */
+#define MODULE_FLAG_ACTIVITY     0x00008000
+
+#define MODULE_NAME_STYLE_FORMAT_MASK    0xf0000000
+#define MODULE_NAME_STYLE_FORMAT_BS      0x10000000 /* base.stamp */
+#define MODULE_NAME_STYLE_FORMAT_BES     0x20000000 /* base.ext.stamp */
+#define MODULE_NAME_STYLE_FORMAT_BSE     0x40000000 /* base.stamp.ext */
+#define MODULE_NAME_STYLE_STAMP_MASK     0x000000ff
+#define MODULE_NAME_STYLE_STAMP_SEC      0x00000001 /* foo.T1332799722 (note STYLE_SEC_PREFIX_CHAR) */
+#define MODULE_NAME_STYLE_STAMP_SEQ      0x00000002 /* foo.0 */
+#define MODULE_NAME_STYLE_STAMP_UTC      0x00000004 /* foo.2012-04-06T13:45:00Z */
+#define MODULE_NAME_STYLE_STAMP_UTC_B    0x00000008 /* ("basic utc") foo.20120406T134500Z */
+#define MODULE_NAME_STYLE_STAMP_LCL      0x00000010 /* foo.2012-04-06T13:45:00-7 */
+#define MODULE_NAME_STYLE_STAMP_LCL_B    0x00000020 /* ("basic local") foo.20120406T134500-7 */
+
+#define STAMP_STYLE_INVALID -1
+#define STAMP_STYLE_NULL     0
+#define STAMP_STYLE_SEC      1
+#define STAMP_STYLE_SEQ      2
+#define STAMP_STYLE_ISO8601  3
+
 #define CHECKPOINT_TEST   0x00000000
 #define CHECKPOINT_FORCE  0x00000001
 #define CHECKPOINT_CRASH  0x00000002
 #define CHECKPOINT_TEST   0x00000000
 #define CHECKPOINT_FORCE  0x00000001
 #define CHECKPOINT_CRASH  0x00000002
 
 typedef struct
 {
 
 typedef struct
 {
+       char *dir;
        char *path;
        char *path;
-       char *fname;
+       char *current_name;
        char *fmt;
        char *fmt;
-       const char *tfmt;
        char *rotate_dir;
        char *rotate_dir;
+       char *base;
+       char *ext;
+       const char *tfmt;
+       uint32_t style_flags;
        uint32_t pvt_flags;
        uint32_t flags;
        uint32_t fails;
        uint32_t pvt_flags;
        uint32_t flags;
        uint32_t fails;
@@ -112,7 +132,7 @@ typedef struct
        size_t file_max;
        size_t all_max;
        uint32_t refcount;
        size_t file_max;
        size_t all_max;
        uint32_t refcount;
-       time_t stamp;
+       time_t timestamp;
        size_t size;
        void *private;
 } asl_out_dst_data_t;
        size_t size;
        void *private;
 } asl_out_dst_data_t;
@@ -138,6 +158,7 @@ typedef struct asl_out_module_s
 typedef struct asl_out_file_list_s
 {
        char *name;
 typedef struct asl_out_file_list_s
 {
        char *name;
+       uint32_t stamp;
        time_t ftime;
        uint32_t seq;
        size_t size;
        time_t ftime;
        uint32_t seq;
        size_t size;
@@ -165,20 +186,22 @@ void asl_out_module_print(FILE *f, asl_out_module_t *m);
 char *asl_out_module_rule_to_string(asl_out_rule_t *r);
 
 int asl_out_mkpath(asl_out_module_t *mlist, asl_out_rule_t *r);
 char *asl_out_module_rule_to_string(asl_out_rule_t *r);
 
 int asl_out_mkpath(asl_out_module_t *mlist, asl_out_rule_t *r);
+int asl_make_database_dir(const char *dir, char **out);
 int asl_out_dst_checkpoint(asl_out_dst_data_t *dst, uint32_t force);
 int asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp);
 int asl_out_dst_set_access(int fd, asl_out_dst_data_t *dst);
 void asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len);
 int asl_out_dst_checkpoint(asl_out_dst_data_t *dst, uint32_t force);
 int asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp);
 int asl_out_dst_set_access(int fd, asl_out_dst_data_t *dst);
 void asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len);
-void asl_make_dst_filename(asl_out_dst_data_t *dst, char *buf, size_t len);
+void asl_dst_make_current_name(asl_out_dst_data_t *dst, uint32_t xflags, char *buf, size_t len);
 
 asl_out_dst_data_t *asl_out_dst_data_retain(asl_out_dst_data_t *dst);
 void asl_out_dst_data_release(asl_out_dst_data_t *dst);
 
 /* rotated log files */
 
 asl_out_dst_data_t *asl_out_dst_data_retain(asl_out_dst_data_t *dst);
 void asl_out_dst_data_release(asl_out_dst_data_t *dst);
 
 /* rotated log files */
-asl_out_file_list_t *asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags);
+asl_out_file_list_t *asl_list_log_files(const char *dir, const char *base, const char *ext, uint32_t flags, bool src);
 asl_out_file_list_t * asl_list_src_files(asl_out_dst_data_t *dst);
 asl_out_file_list_t * asl_list_dst_files(asl_out_dst_data_t *dst);
 void asl_out_file_list_free(asl_out_file_list_t *l);
 asl_out_file_list_t * asl_list_src_files(asl_out_dst_data_t *dst);
 asl_out_file_list_t * asl_list_dst_files(asl_out_dst_data_t *dst);
 void asl_out_file_list_free(asl_out_file_list_t *l);
+asl_out_dst_data_t *asl_out_dest_for_path(asl_out_module_t *m, const char *path);
 
 asl_msg_t *configuration_profile_to_asl_msg(const char *ident);
 
 
 asl_msg_t *configuration_profile_to_asl_msg(const char *ident);
 
index 5bd090cd3967d5e2240178e19dc5a4664f915330..1dcfab1579a2e7819923598cf4300b5c67886d48 100644 (file)
@@ -36,7 +36,6 @@
 
 #define DEFAULT_MAX_RECORDS 2000
 #define DEFAULT_MAX_STRING_MEMORY 4096000
 
 #define DEFAULT_MAX_RECORDS 2000
 #define DEFAULT_MAX_STRING_MEMORY 4096000
-#define MEM_STRING_HEADER_SIZE 8
 
 #define forever for(;;)
 
 
 #define forever for(;;)
 
@@ -59,8 +58,8 @@ asl_memory_statistics(asl_memory_t *s, asl_msg_t **msg)
 
        for (i = 0; i < s->string_count; i++)
        {
 
        for (i = 0; i < s->string_count; i++)
        {
-               size += MEM_STRING_HEADER_SIZE;
-               if (((mem_string_t *)s->string_cache[i])->str != NULL) size += (strlen(((mem_string_t *)s->string_cache[i])->str) + 1);
+               size += sizeof(mem_string_t);
+               if (s->string_cache[i]->str != NULL) size += (strlen(s->string_cache[i]->str) + 1);
        }
 
        snprintf(str, sizeof(str), "%llu", size);
        }
 
        snprintf(str, sizeof(str), "%llu", size);
@@ -78,10 +77,10 @@ asl_memory_statistics(asl_memory_t *s, asl_msg_t **msg)
        snprintf(str, sizeof(str), "%u", s->string_count);
        asl_msg_set_key_val(out, "StringCount", str);
 
        snprintf(str, sizeof(str), "%u", s->string_count);
        asl_msg_set_key_val(out, "StringCount", str);
 
-       snprintf(str, sizeof(str), "%u", s->curr_string_mem);
+       snprintf(str, sizeof(str), "%lu", s->curr_string_mem);
        asl_msg_set_key_val(out, "StringMemory", str);
 
        asl_msg_set_key_val(out, "StringMemory", str);
 
-       snprintf(str, sizeof(str), "%u", s->max_string_mem);
+       snprintf(str, sizeof(str), "%lu", s->max_string_mem);
        asl_msg_set_key_val(out, "MaxStringMemory", str);
 
        *msg = out;
        asl_msg_set_key_val(out, "MaxStringMemory", str);
 
        *msg = out;
@@ -91,35 +90,45 @@ asl_memory_statistics(asl_memory_t *s, asl_msg_t **msg)
 uint32_t
 asl_memory_close(asl_memory_t *s)
 {
 uint32_t
 asl_memory_close(asl_memory_t *s)
 {
-       uint32_t i;
-
        if (s == NULL) return ASL_STATUS_OK;
        if (s == NULL) return ASL_STATUS_OK;
+       
+       dispatch_sync(s->queue, ^{
+               uint32_t i;
 
 
-       if (s->record != NULL)
-       {
-               for (i = 0; i < s->record_count; i++)
+               if (s->record != NULL)
                {
                {
-                       if (s->record[i] != NULL) free(s->record[i]);
-                       s->record[i] = NULL;
-               }
+                       for (i = 0; i < s->record_count; i++)
+                       {
+                               free(s->record[i]);
+                               s->record[i] = NULL;
+                       }
 
 
-               free(s->record);
-               s->record = NULL;
-       }
+                       free(s->record);
+                       s->record = NULL;
+               }
 
 
-       if (s->buffer_record != NULL) free(s->buffer_record);
+               free(s->buffer_record);
+               s->buffer_record = NULL;
 
 
-       if (s->string_cache != NULL)
-       {
-               for (i = 0; i < s->string_count; i++)
+               if (s->string_cache != NULL)
                {
                {
-                       if (s->string_cache[i] != NULL) free(s->string_cache[i]);
-                       s->string_cache[i] = NULL;
+                       for (i = 0; i < s->string_count; i++)
+                       {
+                               if (s->string_cache[i] != NULL)
+                               {
+                                       free(s->string_cache[i]->str);
+                                       free(s->string_cache[i]);
+                               }
+
+                               s->string_cache[i] = NULL;
+                       }
+
+                       free(s->string_cache);
+                       s->string_cache = NULL;
                }
                }
+       });
 
 
-               free(s->string_cache);
-               s->string_cache = NULL;
-       }
+       dispatch_release(s->queue);
 
        free(s);
 
 
        free(s);
 
@@ -140,12 +149,20 @@ asl_memory_open(uint32_t max_records, size_t max_str_mem, asl_memory_t **s)
        out = calloc(1, sizeof(asl_memory_t));
        if (out == NULL) return ASL_STATUS_NO_MEMORY;
 
        out = calloc(1, sizeof(asl_memory_t));
        if (out == NULL) return ASL_STATUS_NO_MEMORY;
 
+       out->queue = dispatch_queue_create("ASL Memory Queue", NULL);
+       if (out->queue == NULL)
+       {
+               free(out);
+               return ASL_STATUS_NO_MEMORY;
+       }
+
        out->max_string_mem = max_str_mem;
 
        out->record_count = max_records;
        out->record = (mem_record_t **)calloc(max_records, sizeof(mem_record_t *));
        if (out->record == NULL)
        {
        out->max_string_mem = max_str_mem;
 
        out->record_count = max_records;
        out->record = (mem_record_t **)calloc(max_records, sizeof(mem_record_t *));
        if (out->record == NULL)
        {
+               dispatch_release(out->queue);
                free(out);
                return ASL_STATUS_NO_MEMORY;
        }
                free(out);
                return ASL_STATUS_NO_MEMORY;
        }
@@ -171,28 +188,67 @@ asl_memory_open(uint32_t max_records, size_t max_str_mem, asl_memory_t **s)
        return ASL_STATUS_OK;
 }
 
        return ASL_STATUS_OK;
 }
 
+static void
+asl_memory_reset(asl_memory_t *s)
+{
+       uint32_t i;
+       if (s == NULL) return;
+
+       /* clear all message records */
+       for (i = 0; i < s->record_count; i++)
+       {
+               memset(s->record[i], 0, sizeof(mem_record_t));
+       }
+
+       /* reset the string cache */
+       if (s->string_cache != NULL)
+       {
+               for (i = 0; i < s->string_count; i++)
+               {
+                       if (s->string_cache[i] != NULL)
+                       {
+                               free(s->string_cache[i]->str);
+                               free(s->string_cache[i]);
+                       }
+                       
+                       s->string_cache[i] = NULL;
+               }
+               
+               free(s->string_cache);
+               s->string_cache = NULL;
+       }
+       
+       s->string_count = 0;
+}
+
 static mem_string_t *
 static mem_string_t *
-mem_string_new(const char *str, uint32_t len, uint32_t hash)
+asl_memory_string_new(const char *str, uint32_t len, uint32_t hash)
 {
        mem_string_t *out;
 {
        mem_string_t *out;
-       size_t ss;
 
        if (str == NULL) return NULL;
 
 
        if (str == NULL) return NULL;
 
-       ss = MEM_STRING_HEADER_SIZE + len + 1;
-       out = (mem_string_t *)calloc(1, ss);
+       out = (mem_string_t *)calloc(1, sizeof(mem_string_t));
        if (out == NULL) return NULL;
 
        out->hash = hash;
        out->refcount = 1;
        if (out == NULL) return NULL;
 
        out->hash = hash;
        out->refcount = 1;
+       out->str = malloc(len + 1);
+       if (out->str == NULL)
+       {
+               free(out);
+               return NULL;
+       }
+       
        memcpy(out->str, str, len);
        memcpy(out->str, str, len);
+       out->str[len] = 0;
 
        return out;
 }
 
 /*
  * Find the first hash greater than or equal to a given hash in the string cache.
 
        return out;
 }
 
 /*
  * Find the first hash greater than or equal to a given hash in the string cache.
- * Return s->string_count if hash is greater that or equal to last hash in the string cache.
+ * Return s->string_count if hash is greater than last hash in the string cache.
  * Caller must check if the hashes match or not.
  *
  * This routine is used both to find strings in the cache and to determine where to insert
  * Caller must check if the hashes match or not.
  *
  * This routine is used both to find strings in the cache and to determine where to insert
@@ -207,7 +263,7 @@ asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash)
        if (s->string_count == 0) return 0;
        if (s->string_count == 1)
        {
        if (s->string_count == 0) return 0;
        if (s->string_count == 1)
        {
-               ms = (mem_string_t *)s->string_cache[0];
+               ms = s->string_cache[0];
                if (hash < ms->hash) return 0;
                return 1;
        }
                if (hash < ms->hash) return 0;
                return 1;
        }
@@ -218,13 +274,13 @@ asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash)
 
        while (range > 1)
        {
 
        while (range > 1)
        {
-               ms = (mem_string_t *)s->string_cache[mid];
+               ms = s->string_cache[mid];
 
                if (hash == ms->hash)
                {
                        while (mid > 0)
                        {
 
                if (hash == ms->hash)
                {
                        while (mid > 0)
                        {
-                               ms = (mem_string_t *)s->string_cache[mid - 1];
+                               ms = s->string_cache[mid - 1];
                                if (hash != ms->hash) break;
                                mid--;
                        }
                                if (hash != ms->hash) break;
                                mid--;
                        }
@@ -233,7 +289,7 @@ asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash)
                }
                else
                {
                }
                else
                {
-                       ms = (mem_string_t *)s->string_cache[mid];
+                       ms = s->string_cache[mid];
                        if (hash < ms->hash) top = mid;
                        else bot = mid;
                }
                        if (hash < ms->hash) top = mid;
                        else bot = mid;
                }
@@ -242,10 +298,10 @@ asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash)
                mid = bot + (range / 2);
        }
 
                mid = bot + (range / 2);
        }
 
-       ms = (mem_string_t *)s->string_cache[bot];
+       ms = s->string_cache[bot];
        if (hash <= ms->hash) return bot;
 
        if (hash <= ms->hash) return bot;
 
-       ms = (mem_string_t *)s->string_cache[top];
+       ms = s->string_cache[top];
        if (hash <= ms->hash) return top;
 
        return s->string_count;
        if (hash <= ms->hash) return top;
 
        return s->string_count;
@@ -274,11 +330,11 @@ asl_memory_string_retain(asl_memory_t *s, const char *str, int create)
        /* asl_memory_string_cache_search_hash just tells us where to look */
        if (where < s->string_count)
        {
        /* asl_memory_string_cache_search_hash just tells us where to look */
        if (where < s->string_count)
        {
-               while (((mem_string_t *)(s->string_cache[where]))->hash == hash)
+               while (s->string_cache[where]->hash == hash)
                {
                {
-                       if (!strcmp(str, ((mem_string_t *)(s->string_cache[where]))->str))
+                       if (!strcmp(str, s->string_cache[where]->str))
                        {
                        {
-                               ((mem_string_t *)(s->string_cache[where]))->refcount++;
+                               s->string_cache[where]->refcount++;
                                return s->string_cache[where];
                        }
 
                                return s->string_cache[where];
                        }
 
@@ -290,26 +346,20 @@ asl_memory_string_retain(asl_memory_t *s, const char *str, int create)
        if (create == 0) return NULL;
 
        /* create a new mem_string_t and insert into the cache at index 'where' */
        if (create == 0) return NULL;
 
        /* create a new mem_string_t and insert into the cache at index 'where' */
-       if (s->string_count == 0)
-       {
-               s->string_cache = (void **)calloc(1, sizeof(void *));
-       }
-       else
-       {
-               s->string_cache = (void **)reallocf(s->string_cache, (s->string_count + 1) * sizeof(void *));
-               for (i = s->string_count; i > where; i--) s->string_cache[i] = s->string_cache[i - 1];
-       }
-
+       new = asl_memory_string_new(str, len, hash);
+       if (new == NULL) return NULL;
+       
+       s->string_cache = (mem_string_t **)reallocf(s->string_cache, (s->string_count + 1) * sizeof(void *));
        if (s->string_cache == NULL)
        {
                s->string_count = 0;
        if (s->string_cache == NULL)
        {
                s->string_count = 0;
+               free(new);
                return NULL;
        }
 
                return NULL;
        }
 
-       new = mem_string_new(str, len, hash);
-       if (new == NULL) return NULL;
+       for (i = s->string_count; i > where; i--) s->string_cache[i] = s->string_cache[i - 1];
 
 
-       s->curr_string_mem += (MEM_STRING_HEADER_SIZE + len + 1);
+       s->curr_string_mem += (sizeof(mem_string_t) + len + 1);
        s->string_cache[where] = new;
        s->string_count++;
 
        s->string_cache[where] = new;
        s->string_count++;
 
@@ -328,11 +378,11 @@ asl_memory_string_release(asl_memory_t *s, mem_string_t *m)
        if (m->refcount > 0) return ASL_STATUS_OK;
 
        where = asl_memory_string_cache_search_hash(s, m->hash);
        if (m->refcount > 0) return ASL_STATUS_OK;
 
        where = asl_memory_string_cache_search_hash(s, m->hash);
-       if (((mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK;
+       if (s->string_cache[where]->hash != m->hash) return ASL_STATUS_OK;
 
        while (s->string_cache[where] != m)
        {
 
        while (s->string_cache[where] != m)
        {
-               if (((mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK;
+               if (s->string_cache[where]->hash != m->hash) return ASL_STATUS_OK;
 
                where++;
                if (where >= s->string_count) return ASL_STATUS_OK;
 
                where++;
                if (where >= s->string_count) return ASL_STATUS_OK;
@@ -340,9 +390,12 @@ asl_memory_string_release(asl_memory_t *s, mem_string_t *m)
 
        for (i = where + 1; i < s->string_count; i++) s->string_cache[i - 1] = s->string_cache[i];
 
 
        for (i = where + 1; i < s->string_count; i++) s->string_cache[i - 1] = s->string_cache[i];
 
-       s->curr_string_mem -= (MEM_STRING_HEADER_SIZE + strlen(m->str) + 1);
+       if (m->str == NULL) s->curr_string_mem -= sizeof(mem_string_t);
+       else s->curr_string_mem -= (sizeof(mem_string_t) + strlen(m->str) + 1);
 
 
+       free(m->str);
        free(m);
        free(m);
+
        s->string_count--;
 
        if (s->string_count == 0)
        s->string_count--;
 
        if (s->string_count == 0)
@@ -352,7 +405,7 @@ asl_memory_string_release(asl_memory_t *s, mem_string_t *m)
                return ASL_STATUS_OK;
        }
 
                return ASL_STATUS_OK;
        }
 
-       s->string_cache = (void **)reallocf(s->string_cache, s->string_count * sizeof(void *));
+       s->string_cache = (mem_string_t **)reallocf(s->string_cache, s->string_count * sizeof(void *));
        if (s->string_cache == NULL)
        {
                s->string_count = 0;
        if (s->string_cache == NULL)
        {
                s->string_count = 0;
@@ -520,15 +573,7 @@ asl_memory_message_encode(asl_memory_t *s, asl_msg_t *msg)
                        v = NULL;
                        if (val != NULL) v = asl_memory_string_retain(s, val, 1);
 
                        v = NULL;
                        if (val != NULL) v = asl_memory_string_retain(s, val, 1);
 
-                       if (r->kvcount == 0)
-                       {
-                               r->kvlist = (mem_string_t **)calloc(2, sizeof(mem_string_t *));
-                       }
-                       else
-                       {
-                               r->kvlist = (mem_string_t **)reallocf(r->kvlist, (r->kvcount + 2) * sizeof(mem_string_t *));
-                       }
-
+                       r->kvlist = (mem_string_t **)reallocf(r->kvlist, (r->kvcount + 2) * sizeof(mem_string_t *));
                        if (r->kvlist == NULL)
                        {
                                asl_memory_record_clear(s, r);
                        if (r->kvlist == NULL)
                        {
                                asl_memory_record_clear(s, r);
@@ -546,45 +591,58 @@ asl_memory_message_encode(asl_memory_t *s, asl_msg_t *msg)
 uint32_t
 asl_memory_save(asl_memory_t *s, asl_msg_t *msg, uint64_t *mid)
 {
 uint32_t
 asl_memory_save(asl_memory_t *s, asl_msg_t *msg, uint64_t *mid)
 {
-       uint32_t status;
-       mem_record_t *t;
+       __block uint32_t status;
 
        if (s == NULL) return ASL_STATUS_INVALID_STORE;
        if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE;
 
 
        if (s == NULL) return ASL_STATUS_INVALID_STORE;
        if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE;
 
-       /* asl_memory_message_encode creates and caches strings */
-       status = asl_memory_message_encode(s, msg);
-       if (status != ASL_STATUS_OK) return status;
-
-       if (*mid != 0)
-       {
-               s->buffer_record->mid = *mid;
-       }
-       else
-       {
-               s->buffer_record->mid = asl_core_new_msg_id(0);
-               *mid = s->buffer_record->mid;
-       }
-
-       /* clear the first record */
-       t = s->record[s->record_first];
-       asl_memory_record_clear(s, t);
-
-       /* add the new record to the record list (swap in the buffer record) */
-       s->record[s->record_first] = s->buffer_record;
-       s->buffer_record = t;
-
-       /* record list is a circular queue */
-       s->record_first++;
-       if (s->record_first >= s->record_count) s->record_first = 0;
+       dispatch_sync(s->queue, ^{
+               mem_record_t *t;
 
 
-       /* delete records if too much memory is in use */
-       while (s->curr_string_mem > s->max_string_mem)
-       {
-               asl_memory_record_clear(s, s->record[s->record_first]);
-               s->record_first++;
-               if (s->record_first >= s->record_count) s->record_first = 0;
-       }
+               /* asl_memory_message_encode creates and caches strings */
+               status = asl_memory_message_encode(s, msg);
+               if (status == ASL_STATUS_OK)
+               {
+                       uint32_t loop_start_index = s->record_first;
+       
+                       if (*mid != 0)
+                       {
+                               s->buffer_record->mid = *mid;
+                       }
+                       else
+                       {
+                               s->buffer_record->mid = asl_core_new_msg_id(0);
+                               *mid = s->buffer_record->mid;
+                       }
+                       
+                       /* clear the first record */
+                       t = s->record[s->record_first];
+                       asl_memory_record_clear(s, t);
+                       
+                       /* add the new record to the record list (swap in the buffer record) */
+                       s->record[s->record_first] = s->buffer_record;
+                       s->buffer_record = t;
+                       
+                       /* record list is a circular queue */
+                       s->record_first++;
+                       if (s->record_first >= s->record_count) s->record_first = 0;
+                       
+                       /* delete records if too much memory is in use */
+                       while (s->curr_string_mem > s->max_string_mem)
+                       {
+                               asl_memory_record_clear(s, s->record[s->record_first]);
+                               s->record_first++;
+                               if (s->record_first >= s->record_count) s->record_first = 0;
+                               if (s->record_first == loop_start_index)
+                               {
+                                       /* The entire ring has been cleared.  This should never happen. */
+                                       asl_memory_reset(s);
+                                       status = ASL_STATUS_FAILED;
+                                       break;
+                               }
+                       }
+               }
+       });
 
        return status;
 }
 
        return status;
 }
@@ -728,9 +786,9 @@ asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, asl_msg_t **out)
                key = NULL;
                val = NULL;
 
                key = NULL;
                val = NULL;
 
-               if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) key = r->kvlist[i]->str;
+               if (r->kvlist[i] != NULL) key = r->kvlist[i]->str;
                i++;
                i++;
-               if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) val = r->kvlist[i]->str;
+               if (r->kvlist[i] != NULL) val = r->kvlist[i]->str;
 
                if (key != NULL) asl_msg_set_key_val(msg, key, val);
        }
 
                if (key != NULL) asl_msg_set_key_val(msg, key, val);
        }
@@ -742,24 +800,32 @@ asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, asl_msg_t **out)
 uint32_t
 asl_memory_fetch(asl_memory_t *s, uint64_t mid, asl_msg_t **msg, int32_t ruid, int32_t rgid)
 {
 uint32_t
 asl_memory_fetch(asl_memory_t *s, uint64_t mid, asl_msg_t **msg, int32_t ruid, int32_t rgid)
 {
-       uint32_t i, status;
+       __block uint32_t status;
 
        if (s == NULL) return ASL_STATUS_INVALID_STORE;
        if (msg == NULL) return ASL_STATUS_INVALID_ARG;
 
 
        if (s == NULL) return ASL_STATUS_INVALID_STORE;
        if (msg == NULL) return ASL_STATUS_INVALID_ARG;
 
-       for (i = 0; i < s->record_count; i++)
-       {
-               if (s->record[i]->mid == 0) break;
+       status = ASL_STATUS_INVALID_ID;
 
 
-               if (s->record[i]->mid == mid)
+       dispatch_sync(s->queue, ^{
+               uint32_t i;
+
+               for (i = 0; i < s->record_count; i++)
                {
                {
-                       status = asl_core_check_access(s->record[i]->ruid, s->record[i]->rgid, ruid, rgid, s->record[i]->flags);
-                       if (status != ASL_STATUS_OK) return status;
-                       return asl_memory_message_decode(s, s->record[i], msg);
+                       if (s->record[i]->mid == 0) break;
+
+                       if (s->record[i]->mid == mid)
+                       {
+                               status = asl_core_check_access(s->record[i]->ruid, s->record[i]->rgid, ruid, rgid, s->record[i]->flags);
+                               if (status != ASL_STATUS_OK) break;
+
+                               status = asl_memory_message_decode(s, s->record[i], msg);
+                               break;
+                       }
                }
                }
-       }
+       });
 
 
-       return ASL_STATUS_INVALID_ID;
+       return status;
 }
 
 static mem_record_t *
 }
 
 static mem_record_t *
@@ -1190,8 +1256,8 @@ asl_memory_slow_match(asl_memory_t *s, mem_record_t *r, asl_msg_t *rawq)
        return status;
 }
 
        return status;
 }
 
-uint32_t
-asl_memory_match_restricted_uuid(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, uint32_t duration, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str)
+static uint32_t
+asl_memory_match_restricted_uuid_internal(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, uint32_t duration, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str)
 {
        uint32_t status, i, where, start, j, do_match, did_match, rescount, *qtype;
        mem_record_t **qp;
 {
        uint32_t status, i, where, start, j, do_match, did_match, rescount, *qtype;
        mem_record_t **qp;
@@ -1199,9 +1265,6 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, asl_msg_list_t *query, asl_msg
        size_t qcount;
        struct timeval now, finish;
 
        size_t qcount;
        struct timeval now, finish;
 
-       if (s == NULL) return ASL_STATUS_INVALID_STORE;
-       if (res == NULL) return ASL_STATUS_INVALID_ARG;
-
        qp = NULL;
        qtype = NULL;
        rescount = 0;
        qp = NULL;
        qtype = NULL;
        rescount = 0;
@@ -1430,8 +1493,32 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, asl_msg_list_t *query, asl_msg
        return ASL_STATUS_OK;
 }
 
        return ASL_STATUS_OK;
 }
 
+uint32_t
+asl_memory_match_restricted_uuid(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, uint32_t duration, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str)
+{
+       __block uint32_t status;
+       if (s == NULL) return ASL_STATUS_INVALID_STORE;
+       if (res == NULL) return ASL_STATUS_INVALID_ARG;
+       
+       dispatch_sync(s->queue, ^{
+               status = asl_memory_match_restricted_uuid_internal(s, query, res, last_id, start_id, count, duration, direction, ruid, rgid, uuid_str);
+       });
+       
+       return status;
+}
+
 uint32_t
 asl_memory_match(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid)
 {
 uint32_t
 asl_memory_match(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid)
 {
-       return asl_memory_match_restricted_uuid(s, query, res, last_id, start_id, count, 0, direction, ruid, rgid, NULL);
+       __block uint32_t status;
+       if (s == NULL) return ASL_STATUS_INVALID_STORE;
+       if (res == NULL) return ASL_STATUS_INVALID_ARG;
+       
+       dispatch_sync(s->queue, ^{
+               status = asl_memory_match_restricted_uuid_internal(s, query, res, last_id, start_id, count, 0, direction, ruid, rgid, NULL);
+       });
+
+       return status;
 }
 }
index 3a1a30a9e9ef34fe6349f385dd36c68fac0859dd..846dc57e8fca6e29e3f7ce828475516c0c797f85 100644 (file)
 #define __ASL_MEMORY_H__
 #include <stdint.h>
 #include <asl.h>
 #define __ASL_MEMORY_H__
 #include <stdint.h>
 #include <asl.h>
+#include <dispatch/dispatch.h>
 
 typedef struct
 {
        uint32_t hash;
        uint32_t refcount;
 
 typedef struct
 {
        uint32_t hash;
        uint32_t refcount;
-       char str[];
+       char *str;
 } mem_string_t;
 
 typedef struct
 {
        uint64_t mid;
        uint64_t time;
 } mem_string_t;
 
 typedef struct
 {
        uint64_t mid;
        uint64_t time;
-       uint32_t nano;
-       uint8_t unused_0;
-       uint8_t level;
-       uint16_t flags;
-       uint32_t pid;
-       uint32_t uid;
-       uint32_t gid;
-       uint32_t ruid;
-       uint32_t rgid;
-       uint32_t refpid;
        uint64_t os_activity_id;
        uint64_t os_activity_id;
-       uint32_t kvcount;
        mem_string_t *host;
        mem_string_t *sender;
        mem_string_t *sender_mach_uuid;
        mem_string_t *host;
        mem_string_t *sender;
        mem_string_t *sender_mach_uuid;
@@ -57,18 +47,30 @@ typedef struct
        mem_string_t *refproc;
        mem_string_t *session;
        mem_string_t **kvlist;
        mem_string_t *refproc;
        mem_string_t *session;
        mem_string_t **kvlist;
+       uint32_t nano;
+       uint32_t pid;
+       uint32_t uid;
+       uint32_t gid;
+       uint32_t ruid;
+       uint32_t rgid;
+       uint32_t refpid;
+       uint32_t kvcount;
+       uint16_t flags;
+       uint8_t level;
+       uint8_t unused_0;
 } mem_record_t;
 
 typedef struct
 {
 } mem_record_t;
 
 typedef struct
 {
+       mem_string_t **string_cache;
+       mem_record_t **record;
+       mem_record_t *buffer_record;
        uint32_t string_count;
        uint32_t string_count;
-       void **string_cache;
        uint32_t record_count;
        uint32_t record_first;
        uint32_t record_count;
        uint32_t record_first;
-       mem_record_t **record;
-       mem_record_t *buffer_record;
-       uint32_t max_string_mem;
-       uint32_t curr_string_mem;
+       size_t max_string_mem;
+       size_t curr_string_mem;
+       dispatch_queue_t queue;
 } asl_memory_t;
 
 uint32_t asl_memory_open(uint32_t max_records, size_t max_str_mem, asl_memory_t **s);
 } asl_memory_t;
 
 uint32_t asl_memory_open(uint32_t max_records, size_t max_str_mem, asl_memory_t **s);
index 02eb7e0d439edea0f1b7cf627f417ffb6870c089..ace82324328c03e027e6fee76c743d1e1886b44f 100644 (file)
 /*
 /*
- * Copyright (c) 2007-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <stdio.h>
-#include <dirent.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <errno.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <servers/bootstrap.h>
-#include <bootstrap_priv.h>
-#include <mach/mach.h>
-#include <copyfile.h>
-#include <fcntl.h>
-#include <zlib.h>
-#include <xpc/xpc.h>
-#include <xpc/private.h>
-#include <os/assumes.h>
-#include <vproc_priv.h>
-#include <asl.h>
-#include <asl_private.h>
-#include <asl_core.h>
-#include <asl_file.h>
-#include <asl_store.h>
-#include "asl_common.h"
-
-#define DEFAULT_MAX_SIZE 150000000
-#define IOBUFSIZE 4096
-
-#define DO_ASLDB       0x00000001
-#define DO_MODULE      0x00000002
-#define DO_CHECKPT     0x00000004
-
-#define DEBUG_FLAG_MASK  0xfffffff0
-#define DEBUG_LEVEL_MASK 0x0000000f
-#define DEBUG_STDERR     0x00000010
-#define DEBUG_ASL        0x00000020
-
-#define AUX_URL_MINE "file:///var/log/asl/"
-#define AUX_URL_MINE_LEN 20
-
-/* length of "file://" */
-#define AUX_URL_PATH_OFFSET 7
-
-extern kern_return_t _asl_server_query
-(
- mach_port_t server,
- caddr_t request,
- mach_msg_type_number_t requestCnt,
- uint64_t startid,
- int count,
- int flags,
- caddr_t *reply,
- mach_msg_type_number_t *replyCnt,
- uint64_t *lastid,
- int *status,
- security_token_t *token
-);
-
-/* global */
-static time_t module_ttl;
-static uint32_t debug;
-static int dryrun;
-static int asl_aux_fd = -1;
-static aslclient aslc;
-static mach_port_t asl_server_port;
-static xpc_connection_t listener;
-static dispatch_queue_t serverq;
-
-typedef struct name_list_s
-{
-       char *name;
-       size_t size;
-       struct name_list_s *next;
-} name_list_t;
-
-static const char *
-keep_str(uint8_t mask)
-{
-       static char str[9];
-       uint32_t x = 0;
-
-       memset(str, 0, sizeof(str));
-       if (mask & 0x01) str[x++] = '0';
-       if (mask & 0x02) str[x++] = '1';
-       if (mask & 0x04) str[x++] = '2';
-       if (mask & 0x08) str[x++] = '3';
-       if (mask & 0x10) str[x++] = '4';
-       if (mask & 0x20) str[x++] = '5';
-       if (mask & 0x40) str[x++] = '6';
-       if (mask & 0x80) str[x++] = '7';
-       if (x == 0) str[x++] = '-';
-       return str;
-}
-
-void
-set_debug(int flag, const char *str)
-{
-       int level, x;
-
-       if (str == NULL) x = ASL_LEVEL_ERR;
-       else if (((str[0] == 'L') || (str[0] == 'l')) && ((str[1] >= '0') && (str[1] <= '7')) && (str[2] == '\0')) x = atoi(str+1);
-       else if ((str[0] >= '0') && (str[0] <= '7') && (str[1] == '\0')) x = ASL_LEVEL_CRIT + atoi(str);
-       else x = ASL_LEVEL_ERR;
-
-       if (x <= 0) x = 0;
-       else if (x > 7) x = 7;
-
-       level = debug & DEBUG_LEVEL_MASK;
-       if (x > level) level = x;
-
-       debug = debug & DEBUG_FLAG_MASK;
-       debug |= flag;
-       debug |= level;
-}
-
-void
-debug_log(int level, const char *str, ...)
-{
-       va_list v;
-
-       if ((debug & DEBUG_STDERR) && (level <= (debug & DEBUG_LEVEL_MASK)))
-       {
-               va_start(v, str);
-               vfprintf(stderr, str, v);
-               va_end(v);
-       }
-
-       if (debug & DEBUG_ASL)
-       {
-               char *line = NULL;
-
-               if (aslc == NULL)
-               {
-                       aslc = asl_open("aslmanager", "syslog", 0);
-                       asl_msg_t *msg = asl_msg_new(ASL_TYPE_MSG);
-
-                       asl_msg_set_key_val(msg, ASL_KEY_MSG, "Status Report");
-                       asl_msg_set_key_val(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE);
-                       asl_create_auxiliary_file((asl_object_t)msg, "Status Report", "public.text", &asl_aux_fd);
-                       asl_msg_release(msg);
-               }
-
-               va_start(v, str);
-               vasprintf(&line, str, v);
-               va_end(v);
-
-               if (line != NULL) write(asl_aux_fd, line, strlen(line));
-               free(line);
-       }
-}
-
-__attribute__((noreturn)) static void
-xpc_server_exit(int status)
-{
-       xpc_connection_cancel(listener);
-       xpc_release(listener);
-       dispatch_release(serverq);
-       exit(status);
-}
-
-name_list_t *
-add_to_name_list(name_list_t *l, const char *name, size_t size)
-{
-       name_list_t *e, *x;
-
-       if (name == NULL) return l;
-
-       e = (name_list_t *)calloc(1, sizeof(name_list_t));
-       if (e == NULL) return NULL;
-
-       e->name = strdup(name);
-       if (e->name == NULL)
-       {
-               free(e);
-               return NULL;
-       }
-
-       e->size = size;
-
-       /* list is sorted by name (i.e. primarily by timestamp) */
-       if (l == NULL) return e;
-
-       if (strcmp(e->name, l->name) <= 0)
-       {
-               e->next = l;
-               return e;
-       }
-
-       for (x = l; (x->next != NULL) && (strcmp(e->name, x->next->name) > 0) ; x = x->next);
-
-       e->next = x->next;
-       x->next = e;
-       return l;
-}
-
-void
-free_name_list(name_list_t *l)
-{
-       name_list_t *e;
-
-       while (l != NULL)
-       {
-               e = l;
-               l = l->next;
-               free(e->name);
-               free(e);
-       }
-
-       free(l);
-}
-/*
- * Copy ASL files by reading and writing each record.
- */
-uint32_t
-copy_asl_file(const char *src, const char *dst, mode_t mode)
-{
-       asl_msg_list_t *res;
-       asl_file_t *f;
-       uint32_t status, i;
-       uint64_t mid;
-       size_t rcount;
-
-       if (src == NULL) return ASL_STATUS_INVALID_ARG;
-       if (dst == NULL) return ASL_STATUS_INVALID_ARG;
-
-       f = NULL;
-       status = asl_file_open_read(src, &f);
-       if (status != ASL_STATUS_OK) return status;
-
-       res = NULL;
-       mid = 0;
-
-       res = asl_file_match(f, NULL, &mid, 0, 0, 0, 1);
-       asl_file_close(f);
-
-       if (res == NULL) return ASL_STATUS_OK;
-       rcount = asl_msg_list_count(res);
-       if (rcount == 0)
-       {
-               asl_msg_list_release(res);
-               return ASL_STATUS_OK;
-       }
-
-       f = NULL;
-       status = asl_file_open_write(dst, mode, -1, -1, &f);
-       if (status != ASL_STATUS_OK) return status;
-       if (f == ASL_STATUS_OK) return ASL_STATUS_FAILED;
-
-       f->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID;
-
-       for (i = 0; i < rcount; i++)
-       {
-               mid = 0;
-               status = asl_file_save(f, asl_msg_list_get_index(res, i), &mid);
-               if (status != ASL_STATUS_OK) break;
-       }
-
-       asl_file_close(f);
-       return status;
-}
-
-int
-copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst)
-{
-       int in, out;
-       size_t n;
-       gzFile gz;
-       char buf[IOBUFSIZE];
-
-       in = open(src, O_RDONLY, 0);
-       if (in < 0) return -1;
-
-       out = open(dst, O_WRONLY | O_CREAT, asldst->mode);
-       if (out >= 0) out = asl_out_dst_set_access(out, asldst);
-       if (out < 0)
-       {
-               close(in);
-               return -1;
-       }
-
-       gz = gzdopen(out, "w");
-       if (gz == NULL)
-       {
-               close(in);
-               close(out);
-               return -1;
-       }
-
-       do {
-               n = read(in, buf, sizeof(buf));
-               if (n > 0) gzwrite(gz, buf, n);
-       } while (n == IOBUFSIZE);
-
-       gzclose(gz);
-       close(in);
-       close(out);
-
-       return 0;
-}
-
-void
-filesystem_rename(const char *src, const char *dst)
-{
-       int status = 0;
-
-       debug_log(ASL_LEVEL_NOTICE, "  rename %s ---> %s\n", src, dst);
-       if (dryrun == 1) return;
-
-       status = rename(src, dst);
-       if (status != 0) debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] rename %s ---> %s\n", status, errno, strerror(errno), src, dst);
-}
-
-void
-filesystem_unlink(const char *path)
-{
-       int status = 0;
-       
-       debug_log(ASL_LEVEL_NOTICE, "  remove %s\n", path);
-       if (dryrun == 1) return;
-       
-       status = unlink(path);
-       if (status != 0) debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path);
-}
-
-void
-filesystem_truncate(const char *path)
-{
-       int status = 0;
-       
-       debug_log(ASL_LEVEL_NOTICE, "  truncate %s\n", path);
-       if (dryrun == 1) return;
-       
-       status = truncate(path, 0);
-       if (status != 0) debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path);
-}
-
-void
-filesystem_rmdir(const char *path)
-{
-       int status = 0;
-
-       debug_log(ASL_LEVEL_NOTICE, "  remove directory %s\n", path);
-       if (dryrun == 1) return;
-
-       status = rmdir(path);
-       if (status != 0) debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] rmdir %s\n", status, errno, strerror(errno), path);
-}
-
-int32_t
-filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags)
-{
-       char *dot;
-
-       if ((src == NULL) || (dst == NULL)) return 0;
-
-       dot = strrchr(src, '.');
-       if ((dot != NULL) && (!strcmp(dot, ".gz"))) flags &= ~MODULE_FLAG_COMPRESS;
-
-       if (((flags & MODULE_FLAG_COMPRESS) == 0) && (!strcmp(src, dst))) return 0;
-
-       if (flags & MODULE_FLAG_TYPE_ASL) debug_log(ASL_LEVEL_NOTICE, "  copy asl %s ---> %s\n", src, dst);
-       else if (flags & MODULE_FLAG_COMPRESS) debug_log(ASL_LEVEL_NOTICE, "  copy compress %s ---> %s.gz\n", src, dst);
-       else debug_log(ASL_LEVEL_NOTICE, "  copy %s ---> %s\n", src, dst);
-
-       if (dryrun == 1) return 0;
-
-       if (flags & MODULE_FLAG_TYPE_ASL)
-       {
-               uint32_t status = copy_asl_file(src, dst, asldst->mode);
-               if (status != 0)
-               {
-                       debug_log(ASL_LEVEL_ERR, "  FAILED status %u [%s] asl copy %s ---> %s\n", status, asl_core_error(status), src, dst);
-                       return 0;
-               }
-       }
-       else if (flags & MODULE_FLAG_COMPRESS)
-       {
-               char gzdst[MAXPATHLEN];
-
-               snprintf(gzdst, sizeof(gzdst), "%s.gz", dst);
-
-               int status = copy_compress_file(asldst, src, gzdst);
-               if (status != 0)
-               {
-                       debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] copy & compress %s ---> %s\n", status, errno, strerror(errno), src, dst);
-                       return 0;
-               }
-       }
-       else
-       {
-               int status = copyfile(src, dst, NULL, COPYFILE_ALL | COPYFILE_RECURSIVE);
-               if (status != 0)
-               {
-                       debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] copy %s ---> %s\n", status, errno, strerror(errno), src, dst);
-                       return 0;
-               }
-       }
-
-       return 1;
-}
-
-int
-remove_directory(const char *path)
-{
-       DIR *dp;
-       struct dirent *dent;
-       char *str;
-
-       dp = opendir(path);
-       if (dp == NULL) return 0;
-
-       while ((dent = readdir(dp)) != NULL)
-       {
-               if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
-               asprintf(&str, "%s/%s", path, dent->d_name);
-               if (str != NULL)
-               {
-                       filesystem_unlink(str);
-                       free(str);
-                       str = NULL;
-               }
-       }
-
-       closedir(dp);
-       filesystem_rmdir(path);
-
-       return 0;
-}
-
-/*
- * Determine the age (in whole days) of a YMD file from its name.
- * Also determines UID and GID from ".Unnn.Gnnn" part of file name.
- */
-uint32_t
-ymd_file_age(const char *name, time_t now, uid_t *u, gid_t *g)
-{
-       struct tm ftime;
-       time_t created;
-       uint32_t days;
-       const char *p;
-
-       if (name == NULL) return 0;
-
-       if (now == 0) now = time(NULL);
-
-       memset(&ftime, 0, sizeof(struct tm));
-       ftime.tm_hour = 24;
-
-       /* name is YYYY.MM.DD.<...> */
-
-       if ((name[0] < '0') || (name[0] > '9')) return 0;
-       ftime.tm_year = 1000 * (name[0] - '0');
-
-       if ((name[1] < '0') || (name[1] > '9')) return 0;
-       ftime.tm_year += 100 * (name[1] - '0');
-
-       if ((name[2] < '0') || (name[2] > '9')) return 0;
-       ftime.tm_year += 10 * (name[2] - '0');
-
-       if ((name[3] < '0') || (name[3] > '9')) return 0;
-       ftime.tm_year += name[3] - '0';
-       ftime.tm_year -= 1900;
-
-       if (name[4] != '.') return 0;
-
-       if ((name[5] < '0') || (name[5] > '9')) return 0;
-       ftime.tm_mon = 10 * (name[5] - '0');
-
-       if ((name[6] < '0') || (name[6] > '9')) return 0;
-       ftime.tm_mon += name[6] - '0';
-       ftime.tm_mon -= 1;
-
-       if (name[7] != '.') return 0;
-
-       if ((name[8] < '0') || (name[8] > '9')) return 0;
-       ftime.tm_mday = 10 * (name[8] - '0');
-
-       if ((name[9] < '0') || (name[9] > '9')) return 0;
-       ftime.tm_mday += name[9] - '0';
-
-       if (name[10] != '.') return 0;
-
-       created = mktime(&ftime);
-       if (created > now) return 0;
-
-       days = (now - created) / 86400;
-
-       if (u != NULL)
-       {
-               *u = -1;
-               p = strchr(name+10, 'U');
-               if (p != NULL) *u = atoi(p+1);
-       }
-
-       if (g != NULL)
-       {
-               *g = -1;
-               p = strchr(name+10, 'G');
-               if (p != NULL) *g = atoi(p+1);
-       }
-
-       return days;
-}
-
-void
-aux_url_callback(const char *url)
-{
-       if (url == NULL) return;
-       if (!strncmp(url, AUX_URL_MINE, AUX_URL_MINE_LEN)) filesystem_unlink(url + AUX_URL_PATH_OFFSET);
-}
-
-uint32_t
-ymd_file_filter(const char *name, const char *path, uint32_t keep_mask, mode_t ymd_mode, uid_t ymd_uid, gid_t ymd_gid)
-{
-       asl_file_t *f = NULL;
-       uint8_t km = keep_mask;
-       uint32_t status, len, dstcount = 0;
-       char src[MAXPATHLEN];
-       char dst[MAXPATHLEN];
-
-       if (snprintf(src, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED;
-       if (snprintf(dst, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED;
-       len = strlen(src) - 3;
-       snprintf(dst + len, 4, "tmp");
-
-       //TODO: check if src file is already filtered
-       debug_log(ASL_LEVEL_NOTICE, "  filter %s %s ---> %s\n", src, keep_str(km), dst);
-
-       status = ASL_STATUS_OK;
-
-       if (dryrun == 0)
-       {
-               status = asl_file_open_read(name, &f);
-               if (status != ASL_STATUS_OK) return status;
-
-               status = asl_file_filter_level(f, dst, keep_mask, ymd_mode, ymd_uid, ymd_gid, &dstcount, aux_url_callback);
-               asl_file_close(f);
-       }
-
-       filesystem_unlink(src);
-       if ((status != ASL_STATUS_OK) || (dstcount == 0)) filesystem_unlink(dst);
-       else filesystem_rename(dst, src);
-
-       return status;
-}
-
-/*
- * Used to set config parameters.
- * Line format "= name value"
- */
-static void
-_aslmanager_set_param(asl_out_dst_data_t *dst, char *s)
-{
-       char **l;
-       uint32_t count;
-
-       if (s == NULL) return;
-       if (s[0] == '\0') return;
-
-       /* skip '=' and whitespace */
-       if (*s == '=') s++;
-       while ((*s == ' ') || (*s == '\t')) s++;
-
-       l = explode(s, " \t");
-       if (l == NULL) return;
-
-       for (count = 0; l[count] != NULL; count++);
-
-       /* name is required */
-       if (count == 0)
-       {
-               free_string_list(l);
-               return;
-       }
-
-       /* value is required */
-       if (count == 1)
-       {
-               free_string_list(l);
-               return;
-       }
-
-       if (!strcasecmp(l[0], "aslmanager_debug"))
-       {
-               /* = debug level */
-               set_debug(DEBUG_ASL, l[1]);
-       }
-       else if (!strcasecmp(l[0], "store_ttl"))
-       {
-               /* = store_ttl days */
-               dst->ttl[LEVEL_ALL] = (time_t)atoll(l[1]);
-       }
-       else if (!strcasecmp(l[0], "module_ttl"))
-       {
-               /* = module_ttl days */
-               module_ttl = (time_t)atoll(l[1]);
-       }
-       else if (!strcasecmp(l[0], "max_store_size"))
-       {
-               /* = max_file_size bytes */
-               dst->all_max = atoi(l[1]);
-       }
-       else if (!strcasecmp(l[0], "archive"))
-       {
-               free(dst->rotate_dir);
-               dst->rotate_dir = NULL;
-
-               /* = archive {0|1} path */
-               if (!strcmp(l[1], "1"))
-               {
-                       if (l[2] == NULL) dst->rotate_dir = strdup(PATH_ASL_ARCHIVE);
-                       else dst->rotate_dir = strdup(l[2]);
-               }
-       }
-       else if (!strcasecmp(l[0], "store_path"))
-       {
-               /* = archive path */
-               free(dst->path);
-               dst->path = strdup(l[1]);
-       }
-       else if (!strcasecmp(l[0], "archive_mode"))
-       {
-               dst->mode = strtol(l[1], NULL, 0);
-               if ((dst->mode == 0) && (errno == EINVAL)) dst->mode = 0400;
-       }
-
-       free_string_list(l);
-}
-
-size_t
-directory_size(const char *path)
-{
-       DIR *dp;
-       struct dirent *dent;
-       struct stat sb;
-       size_t size;
-       char *str;
-
-       dp = opendir(path);
-       if (dp == NULL) return 0;
-
-       size = 0;
-       while ((dent = readdir(dp)) != NULL)
-       {
-               if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
-
-               memset(&sb, 0, sizeof(struct stat));
-               str = NULL;
-               asprintf(&str, "%s/%s", path, dent->d_name);
-
-               if ((str != NULL) && (stat(str, &sb) == 0) && S_ISREG(sb.st_mode))
-               {
-                       size += sb.st_size;
-                       free(str);
-               }
-       }
-
-       closedir(dp);
-       return size;
-}
-
-static int
-process_asl_data_store(asl_out_dst_data_t *dst)
-{
-       int32_t today_ymd_stringlen, expire_ymd_stringlen;
-       time_t now, ttl, ymd_expire;
-       struct tm ctm;
-       char today_ymd_string[32], expire_ymd_string[32], *str;
-       DIR *dp;
-       struct dirent *dent;
-       name_list_t *ymd_list, *bb_list, *aux_list, *bb_aux_list, *e;
-       size_t file_size, store_size;
-       struct stat sb;
-
-       ymd_list = NULL;
-       bb_list = NULL;
-       aux_list = NULL;
-       bb_aux_list = NULL;
-       store_size = 0;
-
-       if (dst == NULL) return 0;
-       if (dst->path == NULL) return 0;
-
-       debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
-       debug_log(ASL_LEVEL_NOTICE, "Processing data store %s\n", dst->path);
-
-       if (dst->rotate_dir != NULL)
-       {
-               /* check archive */
-               memset(&sb, 0, sizeof(struct stat));
-               if (stat(dst->rotate_dir, &sb) == 0)
-               {
-                       /* must be a directory */
-                       if (!S_ISDIR(sb.st_mode))
-                       {
-                               debug_log(ASL_LEVEL_ERR, "aslmanager error: archive %s is not a directory", dst->rotate_dir);
-                               return -1;
-                       }
-               }
-               else
-               {
-                       if (errno == ENOENT)
-                       {
-                               /* archive doesn't exist - create it */
-                               if (mkdir(dst->rotate_dir, 0755) != 0)
-                               {
-                                       debug_log(ASL_LEVEL_ERR, "aslmanager error: can't create archive %s: %s\n", dst->rotate_dir, strerror(errno));
-                                       return -1;
-                               }
-                       }
-                       else
-                       {
-                               /* stat failed for some other reason */
-                               debug_log(ASL_LEVEL_ERR, "aslmanager error: can't stat archive %s: %s\n", dst->rotate_dir, strerror(errno));
-                               return -1;
-                       }
-               }
-       }
-
-       chdir(dst->path);
-
-       /* determine current time */
-       now = time(NULL);
-
-       /* ttl 0 means files never expire */
-       ymd_expire = 0;
-       ttl = dst->ttl[LEVEL_ALL] * SECONDS_PER_DAY;
-
-       if ((ttl > 0) && (ttl <= now)) ymd_expire = now - ttl;
-
-       /* construct today's date as YYYY.MM.DD */
-       memset(&ctm, 0, sizeof(struct tm));
-       if (localtime_r((const time_t *)&now, &ctm) == NULL) return -1;
-
-       snprintf(today_ymd_string, sizeof(today_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
-       today_ymd_stringlen = strlen(today_ymd_string);
-
-       /* construct regular file expiry date as YYYY.MM.DD */
-       memset(&ctm, 0, sizeof(struct tm));
-       if (localtime_r((const time_t *)&ymd_expire, &ctm) == NULL) return -1;
-
-       snprintf(expire_ymd_string, sizeof(expire_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
-       expire_ymd_stringlen = strlen(expire_ymd_string);
-
-       debug_log(ASL_LEVEL_NOTICE, "Expiry Date %s\n", expire_ymd_string);
-
-       dp = opendir(dst->path);
-       if (dp == NULL) return -1;
-
-       /* gather a list of YMD files, AUX dirs, BB.AUX dirs, and BB files */
-       while ((dent = readdir(dp)) != NULL)
-       {
-               memset(&sb, 0, sizeof(struct stat));
-               file_size = 0;
-               if (stat(dent->d_name, &sb) == 0) file_size = sb.st_size;
-
-               if ((dent->d_name[0] >= '0') && (dent->d_name[0] <= '9'))
-               {
-                       ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size);
-                       store_size += file_size;
-               }
-               else if (!strncmp(dent->d_name, "AUX.", 4) && (dent->d_name[4] >= '0') && (dent->d_name[4] <= '9') && S_ISDIR(sb.st_mode))
-               {
-                       file_size = directory_size(dent->d_name);
-                       aux_list = add_to_name_list(aux_list, dent->d_name, file_size);
-                       store_size += file_size;
-               }
-               else if (!strncmp(dent->d_name, "BB.AUX.", 7) && (dent->d_name[7] >= '0') && (dent->d_name[7] <= '9') && S_ISDIR(sb.st_mode))
-               {
-                       file_size = directory_size(dent->d_name);
-                       bb_aux_list = add_to_name_list(bb_aux_list, dent->d_name, file_size);
-                       store_size += file_size;
-               }
-               else if (!strncmp(dent->d_name, "BB.", 3) && (dent->d_name[3] >= '0') && (dent->d_name[3] <= '9'))
-               {
-                       bb_list = add_to_name_list(bb_list, dent->d_name, file_size);
-                       store_size += file_size;
-               }
-               else if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
-               {}
-               else if ((!strcmp(dent->d_name, "StoreData")) || (!strcmp(dent->d_name, "SweepStore")))
-               {}
-               else
-               {
-                       debug_log(ASL_LEVEL_ERR, "aslmanager: unexpected file %s in ASL data store\n", dent->d_name);
-               }
-       }
-
-       closedir(dp);
-
-       debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size);
-       debug_log(ASL_LEVEL_NOTICE, "Data Store YMD Files\n");
-       for (e = ymd_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, "        %s   %lu\n", e->name, e->size);
-       debug_log(ASL_LEVEL_NOTICE, "Data Store AUX Directories\n");
-       for (e = aux_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, "        %s   %lu\n", e->name, e->size);
-       debug_log(ASL_LEVEL_NOTICE, "Data Store BB.AUX Directories\n");
-       for (e = bb_aux_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, "     %s   %lu\n", e->name, e->size);
-       debug_log(ASL_LEVEL_NOTICE, "Data Store BB Files\n");
-       for (e = bb_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s   %lu\n", e->name, e->size);
-
-       /* Delete/achive expired YMD files */
-       debug_log(ASL_LEVEL_NOTICE, "Start YMD File Scan\n");
-
-       e = ymd_list;
-       while (e != NULL)
-       {
-               if (strncmp(e->name, expire_ymd_string, expire_ymd_stringlen) <= 0)
-               {
-                       /* file has expired, archive it if required, then unlink it */
-                       if (dst->rotate_dir != NULL)
-                       {
-                               str = NULL;
-                               asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
-                               if (str == NULL) return -1;
-
-                               filesystem_copy(dst, e->name, str, 0);
-                               free(str);
-                       }
-
-                       filesystem_unlink(e->name);
-                       store_size -= e->size;
-                       e->size = 0;
-               }
-               else
-               {
-                       /* check if there are any per-level TTLs and filter the file if required */
-                       uint32_t i, bit, keep_mask;
-                       uid_t ymd_uid = -1;
-                       gid_t ymd_gid = -1;
-                       mode_t ymd_mode = 0600;
-                       uint32_t age = ymd_file_age(e->name, now, &ymd_uid, &ymd_gid);
-
-                       if (age > 0)
-                       {
-                               keep_mask = 0x000000ff;
-                               bit = 1;
-                               for (i = 0; i <= 7; i++)
-                               {
-                                       if ((dst->ttl[i] > 0) && (age >= dst->ttl[i])) keep_mask &= ~bit;
-                                       bit *= 2;
-                               }
-
-                               memset(&sb, 0, sizeof(struct stat));
-                               if (stat(e->name, &sb) == 0) ymd_mode = sb.st_mode & 0777;
-
-                               if (keep_mask != 0x000000ff) ymd_file_filter(e->name, dst->path, keep_mask, ymd_mode, ymd_uid, ymd_gid);
-                       }
-               }
-
-               e = e->next;
-       }
-
-       debug_log(ASL_LEVEL_NOTICE, "Finished YMD File Scan\n");
-
-       /* Delete/achive expired YMD AUX directories */
-       debug_log(ASL_LEVEL_NOTICE, "Start AUX Directory Scan\n");
-
-       e = aux_list;
-       while (e != NULL)
-       {
-               /* stop when a file name/date is after the expire date */
-               if (strncmp(e->name + 4, expire_ymd_string, expire_ymd_stringlen) > 0) break;
-
-               if (dst->rotate_dir != NULL)
-               {
-                       str = NULL;
-                       asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
-                       if (str == NULL) return -1;
-
-                       filesystem_copy(dst, e->name, str, 0);
-                       free(str);
-               }
-
-               remove_directory(e->name);
-               store_size -= e->size;
-               e->size = 0;
-
-               e = e->next;
-       }
-
-       debug_log(ASL_LEVEL_NOTICE, "Finished AUX Directory Scan\n");
-
-       /* Delete/achive expired BB.AUX directories */
-       debug_log(ASL_LEVEL_NOTICE, "Start BB.AUX Directory Scan\n");
-
-       e = bb_aux_list;
-       while (e != NULL)
-       {
-               /* stop when a file name/date is after the expire date */
-               if (strncmp(e->name + 7, today_ymd_string, today_ymd_stringlen) > 0) break;
-
-               if (dst->rotate_dir != NULL)
-               {
-                       str = NULL;
-                       asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
-                       if (str == NULL) return -1;
-
-                       filesystem_copy(dst, e->name, str, 0);
-                       free(str);
-               }
-
-               remove_directory(e->name);
-               store_size -= e->size;
-               e->size = 0;
-
-               e = e->next;
-       }
-
-       debug_log(ASL_LEVEL_NOTICE, "Finished BB.AUX Directory Scan\n");
-
-       /* Delete/achive expired BB files */
-       debug_log(ASL_LEVEL_NOTICE, "Start BB Scan\n");
-
-       e = bb_list;
-       while (e != NULL)
-       {
-               /* stop when a file name/date is after the expire date */
-               if (strncmp(e->name + 3, today_ymd_string, today_ymd_stringlen) > 0) break;
-
-               if (dst->rotate_dir != NULL)
-               {
-                       str = NULL;
-                       asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
-                       if (str == NULL) return -1;
-
-                       /* syslog -x [str] -f [e->name] */
-                       filesystem_copy(dst, e->name, str, 0);
-                       free(str);
-               }
-
-               filesystem_unlink(e->name);
-               store_size -= e->size;
-               e->size = 0;
-
-               e = e->next;
-       }
-
-       debug_log(ASL_LEVEL_NOTICE, "Finished BB Scan\n");
-
-       if (dst->all_max > 0)
-       {
-               /* if data store is over max_size, delete/archive more YMD files */
-               if (store_size > dst->all_max) debug_log(ASL_LEVEL_NOTICE, "Additional YMD Scan\n");
-
-               e = ymd_list;
-               while ((e != NULL) && (store_size > dst->all_max))
-               {
-                       if (e->size != 0)
-                       {
-                               if (strncmp(e->name, today_ymd_string, today_ymd_stringlen) == 0)
-                               {
-                                       /* do not touch active file YYYY.MM.DD.asl */
-                                       if (strcmp(e->name + today_ymd_stringlen, "asl") == 0)
-                                       {
-                                               e = e->next;
-                                               continue;
-                                       }
-                               }
-
-                               if (dst->rotate_dir != NULL)
-                               {
-                                       str = NULL;
-                                       asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
-                                       if (str == NULL) return -1;
-
-                                       /* syslog -x [str] -f [e->name] */
-                                       filesystem_copy(dst, e->name, str, 0);
-                                       free(str);
-                               }
-
-                               filesystem_unlink(e->name);
-                               store_size -= e->size;
-                               e->size = 0;
-                       }
-
-                       e = e->next;
-               }
-
-               /* if data store is over dst->all_max, delete/archive more BB files */
-               if (store_size > dst->all_max) debug_log(ASL_LEVEL_NOTICE, "Additional BB Scan\n");
-
-               e = bb_list;
-               while ((e != NULL) && (store_size > dst->all_max))
-               {
-                       if (e->size != 0)
-                       {
-                               if (dst->rotate_dir != NULL)
-                               {
-                                       str = NULL;
-                                       asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
-                                       if (str == NULL) return -1;
-
-                                       /* syslog -x [str] -f [e->name] */
-                                       filesystem_copy(dst, e->name, str, 0);
-                                       free(str);
-                               }
-
-                               filesystem_unlink(e->name);
-                               store_size -= e->size;
-                               e->size = 0;
-                       }
-
-                       e = e->next;
-               }
-       }
-
-       free_name_list(ymd_list);        
-       free_name_list(bb_list);
-       free_name_list(aux_list);
-       free_name_list(bb_aux_list);
-
-       debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size);
-
-       return 0;
-}
-
-/* move sequenced source files to dst dir, renaming as we go */
-static int
-module_copy_rename(asl_out_dst_data_t *dst)
-{
-       asl_out_file_list_t *src_list, *dst_list, *f, *dst_last;
-       char *base, *dst_dir;
-       char fpathsrc[MAXPATHLEN], fpathdst[MAXPATHLEN];
-       uint32_t src_count, dst_count;
-       int32_t x, moved;
-
-       if (dst == NULL) return -1;
-       if (dst->path == NULL) return -1;
-
-       base = strrchr(dst->path, '/');
-       if (base == NULL) return -1;
-
-       src_list = asl_list_src_files(dst);
-       if (src_list == 0)
-       {
-               debug_log(ASL_LEVEL_INFO, "    no src files\n");
-               return 0;
-       }
-
-       debug_log(ASL_LEVEL_INFO, "    src files\n");
-
-       src_count = 0;
-       for (f = src_list; f != NULL; f = f->next)
-       {
-               debug_log(ASL_LEVEL_INFO, "      %s\n", f->name);
-               src_count++;
-       }
-
-       dst_list = asl_list_dst_files(dst);
-
-       *base = '\0';
-       base++;
-
-       dst_dir = dst->rotate_dir;
-       if (dst_dir == NULL) dst_dir = dst->path;
-
-       dst_count = 0;
-       dst_last = dst_list;
-
-       if (dst_list == NULL) debug_log(ASL_LEVEL_INFO, "    no dst files\n");
-       else debug_log(ASL_LEVEL_INFO, "    dst files\n");
-
-       for (f = dst_list; f != NULL; f = f->next)
-       {
-               debug_log(ASL_LEVEL_INFO, "      %s\n", f->name);
-               dst_last = f;
-               dst_count++;
-       }
-
-       if (dst->flags & MODULE_FLAG_STYLE_SEQ)
-       {
-               for (f = dst_last; f != NULL; f = f->prev)
-               {
-                       int is_gz = 0;
-                       char *dot = strrchr(f->name, '.');
-                       if ((dot != NULL) && (!strcmp(dot, ".gz"))) is_gz = 1;
-
-                       snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst_dir, f->name);
-                       snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d%s", dst_dir, base, f->seq+src_count, (is_gz == 1) ? ".gz" : "");
-                       filesystem_rename(fpathsrc, fpathdst);
-               }
-
-               for (f = src_list, x = 0; f != NULL; f = f->next, x++)
-               {
-                       snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->path, f->name);
-                       snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d", dst_dir, base, x);
-                       moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags);
-                       if (moved != 0)
-                       {
-                               if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc);
-                               else filesystem_unlink(fpathsrc);
-                       }
-               }
-       }
-       else
-       {
-               for (f = src_list; f != NULL; f = f->next)
-               {
-                       /* final / active base stamped file looks like a checkpointed file - ignore it */
-                       if ((dst->flags & MODULE_FLAG_BASESTAMP) && (f->next == NULL)) break;
-
-                       snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->path, f->name);
-
-                       /* MODULE_FLAG_EXTERNAL files are not decorated with a timestamp */
-                       if (dst->flags & MODULE_FLAG_EXTERNAL)
-                       {
-                               char tstamp[32];
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
 
 
-                               asl_make_timestamp(f->ftime, dst->flags, tstamp, sizeof(tstamp));
-                               snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s", dst_dir, base, tstamp);
-                       }
-                       else
-                       {
-                               snprintf(fpathdst, sizeof(fpathdst), "%s/%s", dst_dir, f->name);
-                       }
+#include <asl.h>
+#include <asl_msg.h>
+#include <asl_msg_list.h>
+#include <asl_store.h>
+#include <errno.h>
+#include <vproc_priv.h>
 
 
-                       moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags);
-                       if (moved != 0)
-                       {
-                               if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc);
-                               else filesystem_unlink(fpathsrc);
-                       }
-               }
-       }
+#include "asl_common.h"
+#include "daemon.h"
+#include "cache_delete.h"
 
 
-       asl_out_file_list_free(src_list);
-       asl_out_file_list_free(dst_list);
+/* global */
+bool dryrun;
+uint32_t debug;
+FILE *debugfp;
+dispatch_queue_t work_queue;
 
 
-       if (base != NULL) *--base = '/';
+static dispatch_queue_t server_queue;
+static time_t module_ttl;
+static xpc_connection_t listener;
+static bool main_task_enqueued;
+static bool initial_main_task = true;
+static dispatch_source_t sig_term_src;
 
 
-       return 0;
-}
+/* wait 5 minutes to run main task after being invoked by XPC */
+#define MAIN_TASK_INITIAL_DELAY 300
 
 
-/* delete expired files */
-static int
-module_expire(asl_out_dst_data_t *dst)
+/*
+ * Used to set config parameters.
+ * Line format "= name value"
+ */
+static void
+_aslmanager_set_param(asl_out_dst_data_t *dst, char *s)
 {
 {
-       asl_out_file_list_t *dst_list, *f;
-       char *base, *dst_dir, fpath[MAXPATHLEN];
-       time_t now, ttl, cutoff;
-
-       if (dst == NULL) return -1;
-       if (dst->path == NULL) return -1;
-       if (dst->ttl[LEVEL_ALL] == 0) return 0;
-
-       ttl = 0;
-       if (module_ttl > 0) ttl = module_ttl;
-       else ttl = dst->ttl[LEVEL_ALL];
-
-       ttl *= SECONDS_PER_DAY;
-
-       now = time(NULL);
-       if (ttl > now) return 0;
-
-       cutoff = now - ttl;
+       char **l;
+       uint32_t count;
 
 
-       base = strrchr(dst->path, '/');
-       if (base == NULL) return -1;
+       if (s == NULL) return;
+       if (s[0] == '\0') return;
 
 
-       dst_list = asl_list_dst_files(dst);
+       /* skip '=' and whitespace */
+       if (*s == '=') s++;
+       while ((*s == ' ') || (*s == '\t')) s++;
 
 
-       *base = '\0';
+       l = explode(s, " \t");
+       if (l == NULL) return;
 
 
-       dst_dir = dst->rotate_dir;
-       if (dst_dir == NULL) dst_dir = dst->path;
+       for (count = 0; l[count] != NULL; count++);
 
 
-       if (dst_list == NULL)
-       {
-               debug_log(ASL_LEVEL_INFO, "    no dst files\n");
-       }
-       else
+       /* name is required */
+       if (count == 0)
        {
        {
-               debug_log(ASL_LEVEL_INFO, "    dst files\n");
-               for (f = dst_list; f != NULL; f = f->next) debug_log(ASL_LEVEL_INFO, "      %s\n", f->name);
+               free_string_list(l);
+               return;
        }
 
        }
 
-       for (f = dst_list; f != NULL; f = f->next)
+       /* value is required */
+       if (count == 1)
        {
        {
-               if (f->ftime <= cutoff)
-               {
-                       snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name);
-                       filesystem_unlink(fpath);
-               }
+               free_string_list(l);
+               return;
        }
 
        }
 
-       asl_out_file_list_free(dst_list);
-
-       if (base != NULL) *base = '/';
-
-       return 0;
-}
-
-/* check all_max size and delete files (oldest first) to stay within size limit */
-static int
-module_check_size(asl_out_dst_data_t *dst)
-{
-       asl_out_file_list_t *dst_list, *f, *dst_end;
-       char *base, *dst_dir, fpath[MAXPATHLEN];
-       size_t total;
-
-       if (dst == NULL) return -1;
-       if (dst->path == NULL) return -1;
-
-       if (dst->all_max == 0) return 0;
-
-       dst_list = asl_list_dst_files(dst);
-       if (dst_list == NULL)
+       if (!strcasecmp(l[0], "aslmanager_debug"))
        {
        {
-               debug_log(ASL_LEVEL_INFO, "    no dst files\n");
-               return 0;
+               /* = debug level */
+               set_debug(DEBUG_ASL, l[1]);
        }
        }
-
-       base = NULL;
-       dst_dir = dst->rotate_dir;
-       if (dst_dir == NULL)
+       else if (!strcasecmp(l[0], "store_ttl"))
        {
        {
-               dst_dir = dst->path;
-               base = strrchr(dst->path, '/');
-               if (base == NULL)
-               {
-                       asl_out_file_list_free(dst_list);
-                       return -1;
-               }
-
-               *base = '\0';
+               /* = store_ttl days */
+               dst->ttl[LEVEL_ALL] = asl_core_str_to_time(l[1], SECONDS_PER_DAY);
        }
        }
-
-       debug_log(ASL_LEVEL_INFO, "    dst files\n");
-       dst_end = dst_list;
-       for (f = dst_list; f != NULL; f = f->next)
+       else if (!strcasecmp(l[0], "module_ttl"))
        {
        {
-               dst_end = f;
-               debug_log(ASL_LEVEL_INFO, "      %s size %lu\n", f->name, f->size);
+               /* = module_ttl days */
+               module_ttl = asl_core_str_to_time(l[1], SECONDS_PER_DAY);
        }
        }
-
-       total = 0;
-       for (f = dst_list; f != NULL; f = f->next) total += f->size;
-       
-       for (f = dst_end; (total > dst->all_max) && (f != NULL); f = f->prev)
+       else if (!strcasecmp(l[0], "max_store_size"))
        {
        {
-               snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name);
-               filesystem_unlink(fpath);
-               total -= f->size;
+               /* = max_file_size bytes */
+               dst->all_max = asl_core_str_to_size(l[1]);
        }
        }
-
-       asl_out_file_list_free(dst_list);
-
-       if (base != NULL) *base = '/';
-
-       return 0;
-}
-
-
-static int
-process_module(asl_out_module_t *mod)
-{
-       asl_out_rule_t *r;
-
-       if (mod == NULL) return -1;
-
-       debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
-       debug_log(ASL_LEVEL_NOTICE, "Processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name);
-
-       for (r = mod->ruleset; r != NULL; r = r->next)
+       else if (!strcasecmp(l[0], "archive"))
        {
        {
-               if (r->action == ACTION_OUT_DEST)
-               {
-                       if (r->dst == NULL)
-                       {
-                               debug_log(ASL_LEVEL_NOTICE, "NULL dst data for output rule - skipped\n");
-                       }
-                       else if (r->dst->flags & MODULE_FLAG_ROTATE)
-                       {
-                               debug_log(ASL_LEVEL_NOTICE, "Checking file %s\n", r->dst->path);
-                               debug_log(ASL_LEVEL_NOTICE, "- Rename, move to destination directory, and compress as required\n");
-
-                               module_copy_rename(r->dst);
-
-                               if (r->dst->ttl[LEVEL_ALL] > 0)
-                               {
-                                       debug_log(ASL_LEVEL_NOTICE, "- Check for expired files - TTL = %d days\n", r->dst->ttl[LEVEL_ALL]);
-                                       module_expire(r->dst);
-                               }
+               free(dst->rotate_dir);
+               dst->rotate_dir = NULL;
 
 
-                               if (r->dst->all_max > 0)
-                               {
-                                       debug_log(ASL_LEVEL_NOTICE, "- Check total storage used - MAX = %lu\n", r->dst->all_max);
-                                       module_check_size(r->dst);
-                               }
-                       }
-                       else if ((r->dst->flags & MODULE_FLAG_TYPE_ASL_DIR) && (r->dst->ttl[LEVEL_ALL] > 0))
-                       {
-                               process_asl_data_store(r->dst);
-                       }
+               /* = archive {0|1} path */
+               if (!strcmp(l[1], "1"))
+               {
+                       if (l[2] == NULL) dst->rotate_dir = strdup(PATH_ASL_ARCHIVE);
+                       else dst->rotate_dir = strdup(l[2]);
                }
        }
                }
        }
-
-       debug_log(ASL_LEVEL_NOTICE, "Finished processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name);
-       return 0;
-}
-
-asl_msg_list_t *
-control_query(asl_msg_t *a)
-{
-       asl_msg_list_t *out;
-       char *qstr, *str, *res;
-       uint32_t len, reslen, status;
-       uint64_t cmax, qmin;
-       kern_return_t kstatus;
-       caddr_t vmstr;
-       security_token_t sec;
-
-       if (asl_server_port == MACH_PORT_NULL)
-       {
-               bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
-               if (asl_server_port == MACH_PORT_NULL) return NULL;
-       }
-
-       qstr = asl_msg_to_string((asl_msg_t *)a, &len);
-
-       str = NULL;
-       if (qstr == NULL)
+       else if (!strcasecmp(l[0], "store_path"))
        {
        {
-               asprintf(&str, "1\nQ [= ASLOption control]\n");
+               /* = archive path */
+               free(dst->path);
+               dst->path = strdup(l[1]);
        }
        }
-       else
+       else if (!strcasecmp(l[0], "archive_mode"))
        {
        {
-               asprintf(&str, "1\n%s [= ASLOption control]\n", qstr);
-               free(qstr);
+               dst->mode = strtol(l[1], NULL, 0);
+               if ((dst->mode == 0) && (errno == EINVAL)) dst->mode = 0400;
        }
 
        }
 
-       if (str == NULL) return NULL;
-
-       /* length includes trailing nul */
-       len = strlen(str) + 1;
-       out = NULL;
-       qmin = 0;
-       cmax = 0;
-       sec.val[0] = -1;
-       sec.val[1] = -1;
-
-       res = NULL;
-       reslen = 0;
-       status = ASL_STATUS_OK;
-
-       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
-       if (kstatus != KERN_SUCCESS) return NULL;
-
-       memmove(vmstr, str, len);
-       free(str);
-
-       status = 0;
-       kstatus = _asl_server_query(asl_server_port, vmstr, len, qmin, 1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec);
-       if (kstatus != KERN_SUCCESS) return NULL;
-
-       if (res == NULL) return NULL;
-
-       out = asl_msg_list_from_string(res);
-       vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
-
-       return out;
-}
-
-int
-checkpoint(const char *name)
-{
-       /* send checkpoint message to syslogd */
-       debug_log(ASL_LEVEL_NOTICE, "Checkpoint module %s\n", (name == NULL) ? "*" : name);
-       if (dryrun != 0) return 0;
-
-       asl_msg_t *qmsg = asl_msg_new(ASL_TYPE_QUERY);
-       char *tmp = NULL;
-       asl_msg_list_t *res;
-
-       asprintf(&tmp, "%s checkpoint", (name == NULL) ? "*" : name);
-       asl_msg_set_key_val_op(qmsg, "action", tmp, ASL_QUERY_OP_EQUAL);
-       free(tmp);
-
-       res = control_query(qmsg);
-
-       asl_msg_list_release(res);
-       return 0;
+       free_string_list(l);
 }
 
 int
 }
 
 int
@@ -1414,9 +137,14 @@ cli_main(int argc, char *argv[])
        int i, work;
        asl_out_module_t *mod, *m;
        asl_out_rule_t *r;
        int i, work;
        asl_out_module_t *mod, *m;
        asl_out_rule_t *r;
-       asl_out_dst_data_t store, *asl_store_dst = NULL;
+       asl_out_dst_data_t store, opts, *asl_store_dst = NULL;
        const char *mname = NULL;
        const char *mname = NULL;
+       char *path = NULL;
+       bool quiet = false;
+       bool cache_delete = false;
+       bool cache_delete_query = false;
 
 
+#if !TARGET_OS_SIMULATOR
        if (geteuid() != 0)
        {
                if (argc == 0) debug = DEBUG_ASL;
        if (geteuid() != 0)
        {
                if (argc == 0) debug = DEBUG_ASL;
@@ -1425,6 +153,7 @@ cli_main(int argc, char *argv[])
                debug_log(ASL_LEVEL_ERR, "aslmanager must be run by root\n");
                exit(1);
        }
                debug_log(ASL_LEVEL_ERR, "aslmanager must be run by root\n");
                exit(1);
        }
+#endif
 
        module_ttl = DEFAULT_TTL;
 
 
        module_ttl = DEFAULT_TTL;
 
@@ -1433,9 +162,21 @@ cli_main(int argc, char *argv[])
        store.ttl[LEVEL_ALL] = DEFAULT_TTL;
        store.all_max = DEFAULT_MAX_SIZE;
 
        store.ttl[LEVEL_ALL] = DEFAULT_TTL;
        store.all_max = DEFAULT_MAX_SIZE;
 
+       memset(&opts, 0, sizeof(opts));
+       opts.ttl[LEVEL_ALL] = DEFAULT_TTL;
+       opts.all_max = DEFAULT_MAX_SIZE;
+
        for (i = 1; i < argc; i++)
        {
        for (i = 1; i < argc; i++)
        {
-               if (!strcmp(argv[i], "-s"))
+               if (!strcmp(argv[i], "-q"))
+               {
+                       quiet = true;
+               }
+               else if (!strcmp(argv[i], "-dd"))
+               {
+                       quiet = true;
+               }
+               else if (!strcmp(argv[i], "-s"))
                {
                        if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
                        {
                {
                        if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
                        {
@@ -1445,14 +186,34 @@ cli_main(int argc, char *argv[])
                }
        }
 
                }
        }
 
+       if (!quiet)
+       {
+               int status = asl_make_database_dir(NULL, NULL);
+               if (status == 0) status = asl_make_database_dir(ASL_INTERNAL_LOGS_DIR, &path);
+               if (status == 0)
+               {
+                       char tstamp[32], *str = NULL;
+
+                       asl_make_timestamp(time(NULL), MODULE_NAME_STYLE_STAMP_LCL_B, tstamp, sizeof(tstamp));
+                       asprintf(&str, "%s/aslmanager.%s", path, tstamp);
+
+                       if (str != NULL)
+                       {
+                               if (status == 0) debugfp = fopen(str, "w");
+                               if (debugfp != NULL) debug |= DEBUG_FILE;
+                               free(str);
+                       }
+               }
+       }
+
        /* get parameters from asl.conf */
        mod = asl_out_module_init();
 
        if (mod != NULL)
        {
        /* get parameters from asl.conf */
        mod = asl_out_module_init();
 
        if (mod != NULL)
        {
-               for (r = mod->ruleset; r != NULL; r = r->next)
+               for (r = mod->ruleset; (r != NULL) && (asl_store_dst == NULL); r = r->next)
                {
                {
-                       if ((asl_store_dst == NULL) && (r->action == ACTION_OUT_DEST) && (!strcmp(r->dst->path, PATH_ASL_STORE)))
+                       if ((r->dst != NULL) && (r->action == ACTION_OUT_DEST) && (!strcmp(r->dst->path, PATH_ASL_STORE)))
                                asl_store_dst = r->dst;
                }
 
                                asl_store_dst = r->dst;
                }
 
@@ -1471,30 +232,55 @@ cli_main(int argc, char *argv[])
        {
                if (!strcmp(argv[i], "-a"))
                {
        {
                if (!strcmp(argv[i], "-a"))
                {
+                       if (asl_store_dst == NULL) asl_store_dst = &store;
+
                        if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->rotate_dir = strdup(argv[++i]);
                        else asl_store_dst->rotate_dir = strdup(PATH_ASL_ARCHIVE);
                        asl_store_dst->mode = 0400;
                }
                else if (!strcmp(argv[i], "-store_ttl"))
                {
                        if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->rotate_dir = strdup(argv[++i]);
                        else asl_store_dst->rotate_dir = strdup(PATH_ASL_ARCHIVE);
                        asl_store_dst->mode = 0400;
                }
                else if (!strcmp(argv[i], "-store_ttl"))
                {
-                       if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->ttl[LEVEL_ALL] = atoi(argv[++i]);
+                       if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+                       {
+                               if (asl_store_dst == NULL) asl_store_dst = &store;
+                               asl_store_dst->ttl[LEVEL_ALL] = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY);
+                       }
                }
                else if (!strcmp(argv[i], "-module_ttl"))
                {
                }
                else if (!strcmp(argv[i], "-module_ttl"))
                {
-                       if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = atoi(argv[++i]);
+                       if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY);
                }
                else if (!strcmp(argv[i], "-ttl"))
                {
                }
                else if (!strcmp(argv[i], "-ttl"))
                {
-                       if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = asl_store_dst->ttl[LEVEL_ALL] = atoi(argv[++i]);
+                       if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+                       {
+                               opts.ttl[LEVEL_ALL] = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY);
+
+                               if (asl_store_dst == NULL) asl_store_dst = &store;
+                               asl_store_dst->ttl[LEVEL_ALL] = opts.ttl[LEVEL_ALL];
+
+                               module_ttl = opts.ttl[LEVEL_ALL];
+                       }
                }
                else if (!strcmp(argv[i], "-size"))
                {
                }
                else if (!strcmp(argv[i], "-size"))
                {
-                       if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->all_max = asl_str_to_size(argv[++i]);
+                       if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+                       {
+                               opts.all_max = asl_core_str_to_size(argv[++i]);
+
+                               if (asl_store_dst == NULL) asl_store_dst = &store;
+                               asl_store_dst->all_max = opts.all_max;
+                       }
                }
                else if (!strcmp(argv[i], "-checkpoint"))
                {
                        work |= DO_CHECKPT;
                }
                }
                else if (!strcmp(argv[i], "-checkpoint"))
                {
                        work |= DO_CHECKPT;
                }
+               else if (!strcmp(argv[i], "-cache_delete"))
+               {
+                       cache_delete = true;
+                       if (((i + 1) < argc) && (argv[i + 1][0] == 'q')) cache_delete_query = true;
+               }
                else if (!strcmp(argv[i], "-module"))
                {
                        work &= ~DO_ASLDB;
                else if (!strcmp(argv[i], "-module"))
                {
                        work &= ~DO_ASLDB;
@@ -1516,18 +302,54 @@ cli_main(int argc, char *argv[])
                }
                else if (!strcmp(argv[i], "-dd"))
                {
                }
                else if (!strcmp(argv[i], "-dd"))
                {
-                       dryrun = 1;
+                       dryrun = true;
 
                        if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]);
 
                        if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]);
-                       else set_debug(DEBUG_STDERR, NULL);
+                       else set_debug(DEBUG_STDERR, "l7");
                }
        }
 
        if (asl_store_dst->path == NULL) asl_store_dst->path = strdup(PATH_ASL_STORE);
 
                }
        }
 
        if (asl_store_dst->path == NULL) asl_store_dst->path = strdup(PATH_ASL_STORE);
 
-       debug_log(ASL_LEVEL_ERR, "aslmanager starting%s\n", (dryrun == 1) ? " dryrun" : "");
+       debug_log(ASL_LEVEL_ERR, "aslmanager starting%s\n", dryrun ? " dryrun" : "");
+
+       if (cache_delete)
+       {
+               size_t curr_size = 0;
+
+               if (cache_delete_task(true, &curr_size) != 0)
+               {
+                       debug_log(ASL_LEVEL_NOTICE, "cache_delete_process failed - can't determine current size\n");
+               }
+               else
+               {
+                       debug_log(ASL_LEVEL_NOTICE, "cache delete current size = %lu\n", curr_size);
+
+                       if (!cache_delete_query)
+                       {
+                               size_t new_size = curr_size - opts.all_max;
+
+                               if (cache_delete_task(false, &new_size) != 0)
+                               {
+                                       debug_log(ASL_LEVEL_NOTICE, "cache_delete_process failed - delete failed\n");
+                               }
+                               else
+                               {
+                                       debug_log(ASL_LEVEL_NOTICE, "cache delete new size = %lu\n", new_size);
+                               }
+                       }
+               }
+
+               asl_out_module_free(mod);
+
+               debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
+               debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", dryrun ? " dryrun" : "");
+               debug_close();
+
+               return 0;
+       }
 
 
-       if (work & DO_ASLDB) process_asl_data_store(asl_store_dst);
+       if (work & DO_ASLDB) process_asl_data_store(asl_store_dst, &opts);
 
        if (work & DO_MODULE)
        {
 
        if (work & DO_MODULE)
        {
@@ -1537,9 +359,13 @@ cli_main(int argc, char *argv[])
                {
                        for (m = mod; m != NULL; m = m->next)
                        {
                {
                        for (m = mod; m != NULL; m = m->next)
                        {
-                               if ((mname == NULL) || ((m->name != NULL) && (!strcmp(m->name, mname))))
+                               if (mname == NULL)
                                {
                                {
-                                       process_module(m);
+                                       process_module(m, NULL);
+                               }
+                               else if ((m->name != NULL) && (!strcmp(m->name, mname)))
+                               {
+                                       process_module(m, &opts);
                                }
                        }
                }
                                }
                        }
                }
@@ -1548,12 +374,43 @@ cli_main(int argc, char *argv[])
        asl_out_module_free(mod);
 
        debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
        asl_out_module_free(mod);
 
        debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
-       debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", (dryrun == 1) ? " dryrun" : "");
-       if (asl_aux_fd >= 0) asl_close_auxiliary_file(asl_aux_fd);
+       debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", dryrun ? " dryrun" : "");
+       debug_close();
 
        return 0;
 }
 
 
        return 0;
 }
 
+/* dispatched on server_queue, dispatches to work_queue */
+void
+main_task(void)
+{
+       /* if main task is already running or queued, do nothing */
+       if (main_task_enqueued) return;
+
+       main_task_enqueued = true;
+       xpc_transaction_begin();
+
+       if (initial_main_task)
+       {
+               initial_main_task = false;
+               dispatch_time_t delay = dispatch_walltime(NULL, MAIN_TASK_INITIAL_DELAY * NSEC_PER_SEC);
+
+               dispatch_after(delay, work_queue, ^{
+                       cli_main(0, NULL);
+                       main_task_enqueued = false;
+                       xpc_transaction_end();
+               });
+       }
+       else
+       {
+               dispatch_async(work_queue, ^{
+                       cli_main(0, NULL);
+                       main_task_enqueued = false;
+                       xpc_transaction_end();
+               });
+       }
+}
+
 static void
 accept_connection(xpc_connection_t peer)
 {
 static void
 accept_connection(xpc_connection_t peer)
 {
@@ -1571,14 +428,16 @@ accept_connection(xpc_connection_t peer)
                         * Some day, we may use the dictionary to pass parameters
                         * to aslmanager, but for now, we ignore the input.
                         */
                         * Some day, we may use the dictionary to pass parameters
                         * to aslmanager, but for now, we ignore the input.
                         */
-                       if (uid == 0) cli_main(0, NULL);
+
+                       if (uid == geteuid())
+                       {
+                               main_task();
+                       }
                }
                else if (xpc_get_type(request) == XPC_TYPE_ERROR)
                {
                        /* disconnect */
                }
                }
                else if (xpc_get_type(request) == XPC_TYPE_ERROR)
                {
                        /* disconnect */
                }
-
-               dispatch_async(serverq, ^__attribute__((noreturn)) { xpc_server_exit(0); });
        });
 
        xpc_connection_resume(peer);
        });
 
        xpc_connection_resume(peer);
@@ -1593,16 +452,32 @@ main(int argc, char *argv[])
 
        if (is_managed == 0) return cli_main(argc, argv);
 
 
        if (is_managed == 0) return cli_main(argc, argv);
 
+       /* Set I/O policy */
+       setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE);
+
        /* XPC server */
        /* XPC server */
-       serverq = dispatch_queue_create("aslmanager", NULL);
-       xpc_track_activity();
+       server_queue = dispatch_queue_create("aslmanager", NULL);
+
+       work_queue = dispatch_queue_create("work queue", NULL);
+
+       /* Exit on SIGTERM */
+       signal(SIGTERM, SIG_IGN);
+       sig_term_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t)SIGTERM, 0, dispatch_get_main_queue());
+       dispatch_source_set_event_handler(sig_term_src, ^{
+               debug_log(ASL_LEVEL_NOTICE, "SIGTERM exit\n");
+               exit(0);
+       });
+
+       dispatch_resume(sig_term_src);
 
        /* Handle incoming messages. */
 
        /* Handle incoming messages. */
-       listener = xpc_connection_create_mach_service("com.apple.aslmanager", serverq, XPC_CONNECTION_MACH_SERVICE_LISTENER);
+       listener = xpc_connection_create_mach_service("com.apple.aslmanager", server_queue, XPC_CONNECTION_MACH_SERVICE_LISTENER);
        xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) {
                if (xpc_get_type(peer) == XPC_TYPE_CONNECTION) accept_connection(peer);
        });
        xpc_connection_resume(listener);
 
        xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) {
                if (xpc_get_type(peer) == XPC_TYPE_CONNECTION) accept_connection(peer);
        });
        xpc_connection_resume(listener);
 
+       cache_delete_register();
+
        dispatch_main();
 }
        dispatch_main();
 }
diff --git a/aslmanager.tproj/cache_delete.c b/aslmanager.tproj/cache_delete.c
new file mode 100644 (file)
index 0000000..1184fc2
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <CacheDelete/CacheDelete.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <asl.h>
+#include "daemon.h"
+
+/* CacheDelete ID (stored in cache delete plist). Must match suggested CacheDelete id naming conventions. */
+#define CACHE_DELETE_ID "com.apple.activity_tracing.cache-delete"
+
+#define CFSTR_FROM_DICT(dict, key) ({ \
+    void *strRef = NULL; \
+    if (dict != NULL) { \
+        strRef = (void *)CFDictionaryGetValue(dict, key); \
+        if ((strRef == NULL) || (CFStringGetTypeID() != CFGetTypeID(strRef))) strRef = NULL; \
+    } \
+    (CFStringRef)strRef; \
+})
+
+#define INT64_FROM_DICT(dict, key) ({ \
+    int64_t value = 0; \
+    if (dict != NULL) { \
+        void *numRef = (void *)CFDictionaryGetValue(dict, key); \
+        if (numRef && (CFNumberGetTypeID() == CFGetTypeID(numRef))) {\
+            if (!CFNumberGetValue(numRef, kCFNumberSInt64Type, &value)) value = 0; \
+        } \
+    } \
+    value; \
+})
+
+static int64_t
+_purgeable(void)
+{
+       size_t psize = 0;
+       int status = cache_delete_task(true, &psize);
+       if (status == 0) return (uint64_t)psize;
+       return 0;
+}
+
+static int64_t
+_purge(int64_t purge_amount_bytes, CacheDeleteUrgency urgency)
+{
+       size_t curr_size, new_size;
+       curr_size = 0;
+
+       int status = cache_delete_task(true, &curr_size);
+       if (status != 0) return 0;
+
+       new_size = curr_size - purge_amount_bytes;
+
+       status = cache_delete_task(false, &new_size);
+       if (status == 0) return new_size;
+
+       return 0;
+}
+
+static bool
+_volume_contains_cached_data(CFStringRef volume)
+{
+    return true;
+}
+
+
+static CFDictionaryRef
+_handle_cache_delete_with_urgency(CFDictionaryRef info, CacheDeleteUrgency urgency, bool purge)
+{
+       xpc_transaction_begin();
+
+    uint64_t amount_requested = INT64_FROM_DICT(info, CFSTR(CACHE_DELETE_AMOUNT_KEY));
+    CFStringRef volume_requested = CFSTR_FROM_DICT(info, CFSTR(CACHE_DELETE_VOLUME_KEY));
+
+    CFMutableDictionaryRef result = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    if (result == NULL)
+       {
+        goto bail;
+    }
+       else if (volume_requested == NULL)
+       {
+        goto bail;
+    }
+    
+    /* TODO: CFStringGetCStringPtr can return NULL */
+//     debug_log(ASL_LEVEL_DEBUG, "CacheDelete request (purge=%d, urgency=%d, volume=%s, amount=%llu).", (int)urgency, CFStringGetCStringPtr(volume_requested, kCFStringEncodingUTF8), amount_requested);
+
+    int64_t amount_purged = 0;
+    
+    if (_volume_contains_cached_data(volume_requested))
+       {
+        if (purge)
+               {
+            amount_purged = _purge(amount_requested, urgency);
+//                     debug_log(ASL_LEVEL_WARNING, "Purged %lld bytes.", amount_purged);
+        }
+               else
+               {
+            amount_purged = _purgeable();
+//                     debug_log(ASL_LEVEL_WARNING, "%lld bytes of purgeable space.", amount_purged);
+        }
+    }
+    
+    CFNumberRef amount_purged_obj = CFNumberCreate(NULL, kCFNumberSInt64Type, &amount_purged);
+    if (amount_purged_obj != NULL)
+       {
+        CFDictionaryAddValue(result, CFSTR(CACHE_DELETE_AMOUNT_KEY), amount_purged_obj);
+        CFRelease(amount_purged_obj);
+    }
+    
+bail:
+
+       xpc_transaction_end();
+   return result;
+}
+
+bool
+cache_delete_register(void)
+{
+    return CacheDeleteRegisterInfoCallbacks(CFSTR(CACHE_DELETE_ID), ^CFDictionaryRef(CacheDeleteUrgency urgency, CFDictionaryRef info) {
+        /* Purgeable Space Request */
+        return _handle_cache_delete_with_urgency(info, urgency, false);
+    }, ^CFDictionaryRef(CacheDeleteUrgency urgency, CFDictionaryRef info) {
+        /* Purge Request */
+        return _handle_cache_delete_with_urgency(info, urgency, true);
+    }, NULL, NULL) == 0;
+}
diff --git a/aslmanager.tproj/cache_delete.h b/aslmanager.tproj/cache_delete.h
new file mode 100644 (file)
index 0000000..22d3b12
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+bool cache_delete_register(void);
diff --git a/aslmanager.tproj/com.apple.activity_tracing.CacheDelete.plist b/aslmanager.tproj/com.apple.activity_tracing.CacheDelete.plist
new file mode 100644 (file)
index 0000000..35633de
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CACHE_DELETE_ID</key>
+       <string>com.apple.activity_tracing.cache-delete</string>
+       <key>CACHE_DELETE_SERVICES</key>
+       <array>
+               <string>PURGE</string>
+       </array>
+</dict>
+</plist>
index 05586a1e41fe69646e0be183b57ec6e47925f398..3e1429c7ba020b9b85044b58e01860bf85a3c2f3 100644 (file)
        <dict>
                <key>com.apple.aslmanager</key>
                <true/>
        <dict>
                <key>com.apple.aslmanager</key>
                <true/>
+               <key>com.apple.activity_tracing.cache-delete</key>
+               <true/>
        </dict>
        <key>EnableTransactions</key>
        </dict>
        <key>EnableTransactions</key>
-       <false/>
+       <true/>
+       <key>EnablePressuredExit</key>
+       <true/>
        <key>POSIXSpawnType</key>
        <string>Interactive</string>
 </dict>
        <key>POSIXSpawnType</key>
        <string>Interactive</string>
 </dict>
diff --git a/aslmanager.tproj/daemon.c b/aslmanager.tproj/daemon.c
new file mode 100644 (file)
index 0000000..ea05d27
--- /dev/null
@@ -0,0 +1,1695 @@
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <asl.h>
+#include <asl_private.h>
+#include <asl_core.h>
+#include <asl_file.h>
+#include <asl_store.h>
+#include <copyfile.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <zlib.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <servers/bootstrap.h>
+#include <bootstrap_priv.h>
+#include <mach/mach.h>
+#include <fcntl.h>
+#include <sys/attr.h>
+#include <dispatch/dispatch.h>
+#include <xpc/xpc.h>
+#include <xpc/private.h>
+#include <os/assumes.h>
+#include <vproc_priv.h>
+#include <libkern/OSAtomic.h>
+#include "daemon.h"
+
+/* global */
+extern bool dryrun;
+extern uint32_t debug;
+extern FILE *debugfp;
+extern dispatch_queue_t work_queue;
+
+static mach_port_t asl_server_port;
+static aslclient aslc;
+static int asl_aux_fd = -1;
+
+extern kern_return_t _asl_server_query
+(
+ mach_port_t server,
+ caddr_t request,
+ mach_msg_type_number_t requestCnt,
+ uint64_t startid,
+ int count,
+ int flags,
+ caddr_t *reply,
+ mach_msg_type_number_t *replyCnt,
+ uint64_t *lastid,
+ int *status,
+ security_token_t *token
+ );
+
+const char *
+keep_str(uint8_t mask)
+{
+       static char str[9];
+       uint32_t x = 0;
+
+       memset(str, 0, sizeof(str));
+       if (mask & 0x01) str[x++] = '0';
+       if (mask & 0x02) str[x++] = '1';
+       if (mask & 0x04) str[x++] = '2';
+       if (mask & 0x08) str[x++] = '3';
+       if (mask & 0x10) str[x++] = '4';
+       if (mask & 0x20) str[x++] = '5';
+       if (mask & 0x40) str[x++] = '6';
+       if (mask & 0x80) str[x++] = '7';
+       if (x == 0) str[x++] = '-';
+       return str;
+}
+
+void
+set_debug(int flag, const char *str)
+{
+       int level, x;
+
+       if (str == NULL) x = ASL_LEVEL_ERR;
+       else if (((str[0] == 'L') || (str[0] == 'l')) && ((str[1] >= '0') && (str[1] <= '7')) && (str[2] == '\0')) x = atoi(str+1);
+       else if ((str[0] >= '0') && (str[0] <= '7') && (str[1] == '\0')) x = ASL_LEVEL_CRIT + atoi(str);
+       else x = ASL_LEVEL_ERR;
+
+       if (x <= 0) x = 0;
+       else if (x > 7) x = 7;
+
+       level = debug & DEBUG_LEVEL_MASK;
+       if (x > level) level = x;
+
+       debug = debug & DEBUG_FLAG_MASK;
+       debug |= flag;
+       debug |= level;
+}
+
+void
+debug_log(int level, char *str, ...)
+{
+       va_list v;
+       char ts[32];
+
+       time_t now = time(NULL);
+       memset(ts, 0, sizeof(ts));
+       strftime(ts, sizeof(ts), "%b %e %T", localtime(&now));
+
+       if ((debug & DEBUG_STDERR) && (level <= (debug & DEBUG_LEVEL_MASK)))
+       {
+               fprintf(stderr, "%s: ", ts);
+               va_start(v, str);
+               vfprintf(stderr, str, v);
+               va_end(v);
+       }
+
+       if ((debug & DEBUG_FILE) && (debugfp != NULL))
+       {
+               fprintf(debugfp, "%s: ", ts);
+               va_start(v, str);
+               vfprintf(debugfp, str, v);
+               va_end(v);
+       }
+
+       if (debug & DEBUG_ASL)
+       {
+               char *line = NULL;
+
+               if (aslc == NULL)
+               {
+                       aslc = asl_open("aslmanager", "syslog", 0);
+                       asl_msg_t *msg = asl_msg_new(ASL_TYPE_MSG);
+
+                       asl_msg_set_key_val(msg, ASL_KEY_MSG, "Status Report");
+                       asl_msg_set_key_val(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE);
+                       asl_create_auxiliary_file((asl_object_t)msg, "Status Report", "public.text", &asl_aux_fd);
+                       asl_msg_release(msg);
+               }
+
+               va_start(v, str);
+               vasprintf(&line, str, v);
+               va_end(v);
+
+               if (line != NULL)
+               {
+                       write(asl_aux_fd, ts, strlen(ts));
+                       write(asl_aux_fd, line, strlen(line));
+               }
+
+               free(line);
+       }
+}
+
+void
+debug_close()
+{
+       if (asl_aux_fd >= 0) asl_close_auxiliary_file(asl_aux_fd);
+       if (debugfp != NULL) fclose(debugfp);
+}
+
+name_list_t *
+add_to_name_list(name_list_t *l, const char *name, size_t size, uint32_t flags)
+{
+       name_list_t *e, *x;
+
+       if (name == NULL) return l;
+
+       e = (name_list_t *)calloc(1, sizeof(name_list_t));
+       if (e == NULL) return NULL;
+
+       e->name = strdup(name);
+       if (e->name == NULL)
+       {
+               free(e);
+               return NULL;
+       }
+
+       e->size = size;
+       e->flags = flags;
+
+       /* list is sorted by name (i.e. primarily by timestamp) */
+       if (l == NULL) return e;
+
+       if (strcmp(e->name, l->name) <= 0)
+       {
+               e->next = l;
+               return e;
+       }
+
+       for (x = l; (x->next != NULL) && (strcmp(e->name, x->next->name) > 0) ; x = x->next);
+
+       e->next = x->next;
+       x->next = e;
+       return l;
+}
+
+void
+free_name_list(name_list_t *l)
+{
+       name_list_t *e;
+
+       while (l != NULL)
+       {
+               e = l;
+               l = l->next;
+               free(e->name);
+               free(e);
+       }
+
+       free(l);
+}
+
+int
+copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst)
+{
+       int in, out;
+       size_t n;
+       gzFile gz;
+       char buf[IOBUFSIZE];
+
+       in = open(src, O_RDONLY, 0);
+       if (in < 0) return -1;
+
+       out = open(dst, O_WRONLY | O_CREAT, asldst->mode & 0666);
+       if (out >= 0) out = asl_out_dst_set_access(out, asldst);
+       if (out < 0)
+       {
+               close(in);
+               return -1;
+       }
+
+       gz = gzdopen(out, "w");
+       if (gz == NULL)
+       {
+               close(in);
+               close(out);
+               return -1;
+       }
+
+       do {
+               n = read(in, buf, sizeof(buf));
+               if (n > 0) gzwrite(gz, buf, n);
+       } while (n == IOBUFSIZE);
+
+       gzclose(gz);
+       close(in);
+       close(out);
+
+       return 0;
+}
+
+void
+filesystem_rename(const char *src, const char *dst)
+{
+       int status = 0;
+
+       debug_log(ASL_LEVEL_NOTICE, "  rename %s ---> %s\n", src, dst);
+       if (dryrun) return;
+
+       status = rename(src, dst);
+       if (status != 0) debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] rename %s ---> %s\n", status, errno, strerror(errno), src, dst);
+}
+
+void
+filesystem_unlink(const char *path)
+{
+       int status = 0;
+
+       debug_log(ASL_LEVEL_NOTICE, "  remove %s\n", path);
+       if (dryrun) return;
+
+       status = unlink(path);
+       if (status != 0) debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path);
+}
+
+void
+filesystem_truncate(const char *path)
+{
+       int status = 0;
+
+       debug_log(ASL_LEVEL_NOTICE, "  truncate %s\n", path);
+       if (dryrun) return;
+
+       status = truncate(path, 0);
+       if (status != 0) debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path);
+}
+
+void
+filesystem_rmdir(const char *path)
+{
+       int status = 0;
+
+       debug_log(ASL_LEVEL_NOTICE, "  remove directory %s\n", path);
+       if (dryrun) return;
+
+       status = rmdir(path);
+       if (status != 0) debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] rmdir %s\n", status, errno, strerror(errno), path);
+}
+
+/*
+ * Copy ASL files by reading and writing each record.
+ */
+static uint32_t
+copy_asl_file(const char *src, const char *dst, mode_t mode)
+{
+       asl_file_t *fin, *fout;
+       uint32_t status;
+
+       if (src == NULL) return ASL_STATUS_INVALID_ARG;
+       if (dst == NULL) return ASL_STATUS_INVALID_ARG;
+
+       fin = NULL;
+       status = asl_file_open_read(src, &fin);
+       if (status != ASL_STATUS_OK) return status;
+
+       fout = NULL;
+       status = asl_file_open_write(dst, mode, -1, -1, &fout);
+       if (status != ASL_STATUS_OK)
+       {
+               asl_file_close(fin);
+               return status;
+       }
+
+       if (fout == NULL)
+       {
+               asl_file_close(fin);
+               return ASL_STATUS_FAILED;
+       }
+
+       fout->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID;
+
+       status = asl_file_read_set_position(fin, ASL_FILE_POSITION_FIRST);
+       if (status != ASL_STATUS_OK)
+       {
+               asl_file_close(fin);
+               asl_file_close(fout);
+               return ASL_STATUS_READ_FAILED;
+       }
+
+       while (status == ASL_STATUS_OK)
+       {
+               uint64_t mid = 0;
+               asl_msg_t *msg = NULL;
+
+               status = asl_file_fetch_next(fin, &msg);
+               if (msg == NULL)
+               {
+                       status = ASL_STATUS_OK;
+                       break;
+               }
+
+               if (status != ASL_STATUS_OK) break;
+
+               status = asl_file_save(fout, msg, &mid);
+               asl_msg_release(msg);
+       }
+
+       asl_file_close(fin);
+       asl_file_close(fout);
+
+       return status;
+}
+
+int32_t
+filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags)
+{
+       char *dot;
+
+       if ((src == NULL) || (dst == NULL)) return 0;
+
+       dot = strrchr(src, '.');
+       if ((dot != NULL) && (!strcmp(dot, ".gz"))) flags &= ~MODULE_FLAG_COMPRESS;
+
+       if (((flags & MODULE_FLAG_COMPRESS) == 0) && (!strcmp(src, dst))) return 0;
+
+       if (flags & MODULE_FLAG_TYPE_ASL) debug_log(ASL_LEVEL_NOTICE, "  copy asl %s ---> %s\n", src, dst);
+       else if (flags & MODULE_FLAG_COMPRESS) debug_log(ASL_LEVEL_NOTICE, "  copy compress %s ---> %s.gz\n", src, dst);
+       else debug_log(ASL_LEVEL_NOTICE, "  copy %s ---> %s\n", src, dst);
+
+       if (dryrun) return 0;
+
+       if (flags & MODULE_FLAG_TYPE_ASL)
+       {
+               uint32_t status = copy_asl_file(src, dst, asldst->mode);
+               if (status != 0)
+               {
+                       debug_log(ASL_LEVEL_ERR, "  FAILED status %u [%s] asl copy %s ---> %s\n", status, asl_core_error(status), src, dst);
+                       return 0;
+               }
+       }
+       else if (flags & MODULE_FLAG_COMPRESS)
+       {
+               char gzdst[MAXPATHLEN];
+
+               snprintf(gzdst, sizeof(gzdst), "%s.gz", dst);
+
+               int status = copy_compress_file(asldst, src, gzdst);
+               if (status != 0)
+               {
+                       debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] copy & compress %s ---> %s\n", status, errno, strerror(errno), src, dst);
+                       return 0;
+               }
+       }
+       else
+       {
+               int status = copyfile(src, dst, NULL, COPYFILE_ALL | COPYFILE_RECURSIVE);
+               if (status != 0)
+               {
+                       debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] copy %s ---> %s\n", status, errno, strerror(errno), src, dst);
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+int32_t
+filesystem_reset_ctime(const char *path)
+{
+       struct attrlist attr_list;
+       struct timespec now;
+
+       debug_log(ASL_LEVEL_NOTICE, "  reset ctime %s\n", path);
+
+       memset(&attr_list, 0, sizeof(attr_list));
+       attr_list.bitmapcount = ATTR_BIT_MAP_COUNT;
+       attr_list.commonattr = ATTR_CMN_CRTIME;
+
+       memset(&now, 0, sizeof(now));
+       now.tv_sec = time(NULL);
+
+       return setattrlist(path, &attr_list, &now, sizeof(now), 0);
+}
+
+int
+remove_directory(const char *path)
+{
+       DIR *dp;
+       struct dirent *dent;
+       char *str;
+
+       dp = opendir(path);
+       if (dp == NULL) return 0;
+
+       while ((dent = readdir(dp)) != NULL)
+       {
+               if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
+               asprintf(&str, "%s/%s", path, dent->d_name);
+               if (str != NULL)
+               {
+                       filesystem_unlink(str);
+                       free(str);
+                       str = NULL;
+               }
+       }
+
+       closedir(dp);
+       filesystem_rmdir(path);
+
+       return 0;
+}
+
+size_t
+directory_size(const char *path)
+{
+       DIR *dp;
+       struct dirent *dent;
+       struct stat sb;
+       size_t size;
+       char *str;
+
+       dp = opendir(path);
+       if (dp == NULL) return 0;
+
+       size = 0;
+       while ((dent = readdir(dp)) != NULL)
+       {
+               if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
+
+               memset(&sb, 0, sizeof(struct stat));
+               str = NULL;
+               asprintf(&str, "%s/%s", path, dent->d_name);
+
+               if ((str != NULL) && (stat(str, &sb) == 0) && S_ISREG(sb.st_mode))
+               {
+                       size += sb.st_size;
+                       free(str);
+               }
+       }
+
+       closedir(dp);
+       return size;
+}
+
+time_t
+parse_ymd_name(const char *name)
+{
+       struct tm ftime;
+       time_t created;
+       int32_t tzh, tzm, sign = -1;
+       const char *x;
+       bool legacy = false;
+
+       if (name == NULL) return -1;
+
+       x = name;
+
+       if ((*x == 'T') || (*x == 't'))
+       {
+               x++;
+               created = atol(x);
+               if ((created == 0) && (*x != '0')) return -1;
+
+               x = strchr(x, '.');
+               if (x == NULL) return -1;
+
+               return created;
+       }
+
+       memset(&ftime, 0, sizeof(ftime));
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_year = 1000 * (*x++ - '0');
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_year += 100 * (*x++ - '0');
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_year += 10 * (*x++ - '0');
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_year += *x++ - '0';
+       ftime.tm_year -= 1900;
+
+       if (*x == '-') x++;
+       else if (*x == '.')
+       {
+               x++;
+               legacy = true;
+       }
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_mon = 10 * (*x++ - '0');
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_mon += *x++ - '0';
+       ftime.tm_mon -= 1;
+
+       if ((*x == '-') || (*x == '.')) x++;
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_mday = 10 * (*x++ - '0');
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_mday += *x++ - '0';
+
+       if (legacy)
+       {
+               if ((*x != '.') && (*x != '\0')) return -1;
+
+               /* assume the file was created at midnight */
+               ftime.tm_hour = 24;
+               ftime.tm_min = 0;
+               ftime.tm_sec = 0;
+               ftime.tm_isdst = -1;
+
+               created = mktime(&ftime);
+               return created;
+       }
+
+       if ((*x != 'T') && (*x != 't')) return 1;
+       x++;
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_hour = 10 * (*x++ - '0');
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_hour += *x++ - '0';
+
+       if (*x == ':') x++;
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_min = 10 * (*x++ - '0');
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_min += *x++ - '0';
+
+       if (*x == ':') x++;
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_sec = 10 * (*x++ - '0');
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       ftime.tm_sec += *x++ - '0';
+
+       if ((*x == 'Z') || (*x == 'z'))
+       {
+               created = timegm(&ftime);
+               return created;
+       }
+
+       if ((*x != '+') && (*x != '-')) return 1;
+
+       if (*x == '-') sign = 1;
+       x++;
+
+       if ((*x < '0') || (*x > '9')) return 1;
+       tzh = 10 * (*x++ - '0');
+
+       if ((*x < '0') || (*x > '9')) tzh /= 10;
+       else tzh += *x++ - '0';
+
+       if (tzh > 23) return 1;
+
+       tzm = 0;
+       if ((*x == ':') || ((*x >= '0') && (*x <= '9')))
+       {
+               if (*x != ':') tzm = 10 * (*x - '0');
+               x++;
+
+               if ((*x < '0') || (*x > '9'))return -1;
+               tzm += *x++ - '0';
+
+               if (tzm > 59) return -1;
+       }
+
+       ftime.tm_sec += (sign * (tzh * SECONDS_PER_HOUR) + (tzm * SECONDS_PER_MINUTE));
+
+       if ((*x != '.') && (*x != '\0')) return -1;
+
+       created = timegm(&ftime);
+       return created;
+}
+
+
+/*
+ * Determine the age (in seconds) of a YMD file from its name.
+ * Also determines UID and GID from ".Unnn.Gnnn" part of file name.
+ */
+uint32_t
+ymd_file_age(const char *name, time_t now, uid_t *u, gid_t *g)
+{
+       struct tm ftime;
+       time_t created;
+       uint32_t seconds;
+       const char *p;
+
+       if (name == NULL) return 0;
+
+       if (now == 0) now = time(NULL);
+
+       memset(&ftime, 0, sizeof(struct tm));
+
+       created = parse_ymd_name(name);
+       if (created < 0) return 0;
+       if (created > now) return 0;
+       seconds = now - created;
+
+       if (u != NULL)
+       {
+               *u = -1;
+               p = strchr(name, 'U');
+               if (p != NULL) *u = atoi(p+1);
+       }
+
+       if (g != NULL)
+       {
+               *g = -1;
+               p = strchr(name, 'G');
+               if (p != NULL) *g = atoi(p+1);
+       }
+
+       return seconds;
+}
+
+
+static void
+aux_url_callback(const char *url)
+{
+       if (url == NULL) return;
+       if (!strncmp(url, AUX_URL_MINE, AUX_URL_MINE_LEN)) filesystem_unlink(url + AUX_URL_PATH_OFFSET);
+}
+
+uint32_t
+ymd_file_filter(const char *name, const char *path, uint32_t keep_mask, mode_t ymd_mode, uid_t ymd_uid, gid_t ymd_gid)
+{
+       asl_file_t *f = NULL;
+       uint8_t km = keep_mask;
+       uint32_t status, len, dstcount = 0;
+       char src[MAXPATHLEN];
+       char dst[MAXPATHLEN];
+
+       if (snprintf(src, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED;
+       if (snprintf(dst, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED;
+       len = strlen(src) - 3;
+       snprintf(dst + len, 4, "tmp");
+
+       //TODO: check if src file is already filtered
+       debug_log(ASL_LEVEL_NOTICE, "  filter %s %s ---> %s\n", src, keep_str(km), dst);
+
+       status = ASL_STATUS_OK;
+
+       if (!dryrun)
+       {
+               status = asl_file_open_read(name, &f);
+               if (status != ASL_STATUS_OK) return status;
+
+               status = asl_file_filter_level(f, dst, keep_mask, ymd_mode, ymd_uid, ymd_gid, &dstcount, aux_url_callback);
+               asl_file_close(f);
+       }
+
+       filesystem_unlink(src);
+       if ((status != ASL_STATUS_OK) || (dstcount == 0)) filesystem_unlink(dst);
+       else filesystem_rename(dst, src);
+
+       return status;
+}
+
+int
+process_asl_data_store(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts)
+{
+       time_t now, midnight, since_midnight;
+       char *str;
+       DIR *dp;
+       struct dirent *dent;
+       name_list_t *ymd_list, *bb_list, *aux_list, *bb_aux_list, *e;
+       size_t file_size, store_size;
+       struct stat sb;
+       char tstr[128];
+       struct tm t_tmp;
+       uint32_t ttl = 0;
+
+       ymd_list = NULL;
+       bb_list = NULL;
+       aux_list = NULL;
+       bb_aux_list = NULL;
+       store_size = 0;
+
+       if (dst == NULL) return 0;
+       if (dst->path == NULL) return 0;
+
+       ttl = dst->ttl[LEVEL_ALL];
+       if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL];
+
+       size_t all_max = dst->all_max;
+       if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max;
+
+       debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
+       debug_log(ASL_LEVEL_NOTICE, "Processing data store %s\n", dst->path);
+
+       if (dst->rotate_dir != NULL)
+       {
+               /* check archive */
+               memset(&sb, 0, sizeof(struct stat));
+               if (stat(dst->rotate_dir, &sb) == 0)
+               {
+                       /* must be a directory */
+                       if (!S_ISDIR(sb.st_mode))
+                       {
+                               debug_log(ASL_LEVEL_ERR, "aslmanager error: archive %s is not a directory", dst->rotate_dir);
+                               return -1;
+                       }
+               }
+               else
+               {
+                       if (errno == ENOENT)
+                       {
+                               /* archive doesn't exist - create it */
+                               if (mkdir(dst->rotate_dir, 0755) != 0)
+                               {
+                                       debug_log(ASL_LEVEL_ERR, "aslmanager error: can't create archive %s: %s\n", dst->rotate_dir, strerror(errno));
+                                       return -1;
+                               }
+                       }
+                       else
+                       {
+                               /* stat failed for some other reason */
+                               debug_log(ASL_LEVEL_ERR, "aslmanager error: can't stat archive %s: %s\n", dst->rotate_dir, strerror(errno));
+                               return -1;
+                       }
+               }
+       }
+
+       chdir(dst->path);
+
+       /* determine current time */
+       now = time(NULL);
+
+       localtime_r(&now, &t_tmp);
+
+       t_tmp.tm_sec = 0;
+       t_tmp.tm_min = 0;
+       t_tmp.tm_hour = 0;
+
+       midnight = mktime(&t_tmp);
+       since_midnight = now - midnight;
+
+       dp = opendir(dst->path);
+       if (dp == NULL) return -1;
+
+       /* gather a list of YMD files, AUX dirs, BB.AUX dirs, and BB files */
+       while ((dent = readdir(dp)) != NULL)
+       {
+               uint32_t file_flags = 0;
+               char *dot = NULL;
+
+               memset(&sb, 0, sizeof(struct stat));
+               file_size = 0;
+               if (stat(dent->d_name, &sb) == 0) file_size = sb.st_size;
+
+               dot = strrchr(dent->d_name, '.');
+               if ((dot != NULL) && !strcmp(dot, ".gz")) file_flags |= NAME_LIST_FLAG_COMPRESSED;
+
+               if ((dent->d_name[0] >= '0') && (dent->d_name[0] <= '9'))
+               {
+                       ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size, file_flags);
+                       store_size += file_size;
+               }
+               else if (((dent->d_name[0] == 'T') || (dent->d_name[0] == 't')) && (dent->d_name[1] >= '0') && (dent->d_name[1] <= '9'))
+               {
+                       ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size, file_flags);
+                       store_size += file_size;
+               }
+               else if (!strncmp(dent->d_name, "AUX.", 4) && (dent->d_name[4] >= '0') && (dent->d_name[4] <= '9') && S_ISDIR(sb.st_mode))
+               {
+                       file_size = directory_size(dent->d_name);
+                       aux_list = add_to_name_list(aux_list, dent->d_name, file_size, file_flags);
+                       store_size += file_size;
+               }
+               else if (!strncmp(dent->d_name, "BB.AUX.", 7) && (dent->d_name[7] >= '0') && (dent->d_name[7] <= '9') && S_ISDIR(sb.st_mode))
+               {
+                       file_size = directory_size(dent->d_name);
+                       bb_aux_list = add_to_name_list(bb_aux_list, dent->d_name, file_size, file_flags);
+                       store_size += file_size;
+               }
+               else if (!strncmp(dent->d_name, "BB.", 3) && (dent->d_name[3] >= '0') && (dent->d_name[3] <= '9'))
+               {
+                       bb_list = add_to_name_list(bb_list, dent->d_name, file_size, file_flags);
+                       store_size += file_size;
+               }
+               else if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
+               {}
+               else if ((!strcmp(dent->d_name, "StoreData")) || (!strcmp(dent->d_name, "SweepStore")))
+               {}
+               else if (!strcmp(dent->d_name, ASL_INTERNAL_LOGS_DIR))
+               {}
+               else
+               {
+                       debug_log(ASL_LEVEL_ERR, "aslmanager: unexpected file %s in ASL data store\n", dent->d_name);
+               }
+       }
+
+       closedir(dp);
+
+       debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size);
+       asl_core_time_to_str(ttl, tstr, sizeof(tstr));
+       debug_log(ASL_LEVEL_NOTICE, "Data Store YMD Files (TTL = %s)\n", tstr);
+       for (e = ymd_list; e != NULL; e = e->next)
+       {
+               uint32_t age = ymd_file_age(e->name, now, NULL, NULL);
+               asl_core_time_to_str(age, tstr, sizeof(tstr));
+               debug_log(ASL_LEVEL_NOTICE, "  %s   %lu (age %s%s)\n", e->name, e->size, tstr, (age > ttl) ? " - expired" : "");
+       }
+
+       debug_log(ASL_LEVEL_NOTICE, "Data Store AUX Directories\n");
+       for (e = aux_list; e != NULL; e = e->next)
+       {
+               uint32_t age = ymd_file_age(e->name + 4, now, NULL, NULL) / SECONDS_PER_DAY;
+               asl_core_time_to_str(age, tstr, sizeof(tstr));
+               debug_log(ASL_LEVEL_NOTICE, "  %s   %lu (age %s)\n", e->name, e->size, tstr, (age > ttl) ? " - expired" : "");
+       }
+
+       debug_log(ASL_LEVEL_NOTICE, "Data Store BB.AUX Directories\n");
+       for (e = bb_aux_list; e != NULL; e = e->next)
+       {
+               uint32_t age = ymd_file_age(e->name + 7, now, NULL, NULL);
+               asl_core_time_to_str(age, tstr, sizeof(tstr));
+               debug_log(ASL_LEVEL_NOTICE, "  %s   %lu (age %s)\n", e->name, e->size, tstr, ((age / SECONDS_PER_DAY) > 0) ? " - expired" : "");
+       }
+
+       debug_log(ASL_LEVEL_NOTICE, "Data Store BB Files\n");
+       for (e = bb_list; e != NULL; e = e->next)
+       {
+               uint32_t age = ymd_file_age(e->name + 3, now, NULL, NULL) / SECONDS_PER_DAY;
+               asl_core_time_to_str(age, tstr, sizeof(tstr));
+               debug_log(ASL_LEVEL_NOTICE, "  %s   %lu (age %s)\n", e->name, e->size, tstr, ((age / SECONDS_PER_DAY) > 0) ? " - expired" : "");
+       }
+
+       /* Delete/achive expired YMD files */
+       debug_log(ASL_LEVEL_NOTICE, "Start YMD File Scan\n");
+
+       e = ymd_list;
+       while (e != NULL)
+       {
+               uid_t ymd_uid = -1;
+               gid_t ymd_gid = -1;
+               uint32_t age = ymd_file_age(e->name, now, &ymd_uid, &ymd_gid);
+
+               if (age > ttl)
+               {
+                       /* file has expired, archive it if required, then unlink it */
+                       if (dst->rotate_dir != NULL)
+                       {
+                               str = NULL;
+                               asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+                               if (str == NULL) return -1;
+
+                               filesystem_copy(dst, e->name, str, 0);
+                               free(str);
+                       }
+
+                       filesystem_unlink(e->name);
+                       store_size -= e->size;
+                       e->size = 0;
+               }
+               else if ((e->flags & NAME_LIST_FLAG_COMPRESSED) == 0)
+               {
+                       uint32_t i, bit, keep_mask;
+                       mode_t ymd_mode = 0600;
+
+                       /* check if there are any per-level TTLs and filter the file if required */
+                       if (age > 0)
+                       {
+                               keep_mask = 0x000000ff;
+                               bit = 1;
+                               for (i = 0; i <= 7; i++)
+                               {
+                                       if ((dst->ttl[i] > 0) && (age >= dst->ttl[i])) keep_mask &= ~bit;
+                                       bit *= 2;
+                               }
+
+                               memset(&sb, 0, sizeof(struct stat));
+                               if (stat(e->name, &sb) == 0) ymd_mode = sb.st_mode & 0777;
+
+                               if (keep_mask != 0x000000ff) ymd_file_filter(e->name, dst->path, keep_mask, ymd_mode, ymd_uid, ymd_gid);
+                       }
+
+                       if ((age > since_midnight) && (dst->flags & MODULE_FLAG_COMPRESS))
+                       {
+                               char gzdst[MAXPATHLEN];
+
+                               snprintf(gzdst, sizeof(gzdst), "%s.gz", e->name);
+                               debug_log(ASL_LEVEL_NOTICE, "  compress %s ---> %s\n", e->name, gzdst);
+
+                               if (!dryrun)
+                               {
+                                       int status = copy_compress_file(dst, e->name, gzdst);
+                                       if (status == 0)
+                                       {
+                                               filesystem_unlink(e->name);
+                                       }
+                                       else
+                                       {
+                                               debug_log(ASL_LEVEL_ERR, "  FAILED status %d errno %d [%s] compress %s ---> %s\n", status, errno, strerror(errno), e->name, gzdst);
+                                               return 0;
+                                       }
+                               }
+                       }
+               }
+
+               e = e->next;
+       }
+
+       debug_log(ASL_LEVEL_NOTICE, "Finished YMD File Scan\n");
+
+       /* Delete/achive expired YMD AUX directories */
+       debug_log(ASL_LEVEL_NOTICE, "Start AUX Directory Scan\n");
+
+       e = aux_list;
+       while (e != NULL)
+       {
+               uint32_t age = ymd_file_age(e->name + 4, now, NULL, NULL);
+
+               if (age > ttl)
+               {
+                       if (dst->rotate_dir != NULL)
+                       {
+                               str = NULL;
+                               asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+                               if (str == NULL) return -1;
+
+                               filesystem_copy(dst, e->name, str, 0);
+                               free(str);
+                       }
+
+                       remove_directory(e->name);
+                       store_size -= e->size;
+                       e->size = 0;
+               }
+
+               e = e->next;
+       }
+
+       debug_log(ASL_LEVEL_NOTICE, "Finished AUX Directory Scan\n");
+
+       /* Delete/achive expired BB.AUX directories */
+       debug_log(ASL_LEVEL_NOTICE, "Start BB.AUX Directory Scan\n");
+
+       e = bb_aux_list;
+       while (e != NULL)
+       {
+               uint32_t age = ymd_file_age(e->name + 7, now, NULL, NULL);
+
+               if (age > 0)
+               {
+                       if (dst->rotate_dir != NULL)
+                       {
+                               str = NULL;
+                               asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+                               if (str == NULL) return -1;
+
+                               filesystem_copy(dst, e->name, str, 0);
+                               free(str);
+                       }
+
+                       remove_directory(e->name);
+                       store_size -= e->size;
+                       e->size = 0;
+               }
+
+               e = e->next;
+       }
+
+       debug_log(ASL_LEVEL_NOTICE, "Finished BB.AUX Directory Scan\n");
+
+       /* Delete/achive expired BB files */
+       debug_log(ASL_LEVEL_NOTICE, "Start BB Scan\n");
+
+       e = bb_list;
+       while (e != NULL)
+       {
+               uint32_t age = ymd_file_age(e->name + 3, now, NULL, NULL);
+
+               if (age > 0)
+               {
+                       if (dst->rotate_dir != NULL)
+                       {
+                               str = NULL;
+                               asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+                               if (str == NULL) return -1;
+
+                               /* syslog -x [str] -f [e->name] */
+                               filesystem_copy(dst, e->name, str, 0);
+                               free(str);
+                       }
+
+                       filesystem_unlink(e->name);
+                       store_size -= e->size;
+                       e->size = 0;
+               }
+
+               e = e->next;
+       }
+
+       debug_log(ASL_LEVEL_NOTICE, "Finished BB Scan\n");
+
+       if (all_max > 0)
+       {
+               /* if data store is over max_size, delete/archive more YMD files */
+               if (store_size > all_max) debug_log(ASL_LEVEL_NOTICE, "Additional YMD Scan\n");
+
+               e = ymd_list;
+               while ((e != NULL) && (store_size > all_max))
+               {
+                       if (e->size != 0)
+                       {
+                               uint32_t age = ymd_file_age(e->name, now, NULL, NULL);
+                               if (age == 0)
+                               {
+                                       /* do not touch active file YYYY.MM.DD.asl */
+                                       e = e->next;
+                                       continue;
+                               }
+
+                               if (dst->rotate_dir != NULL)
+                               {
+                                       str = NULL;
+                                       asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+                                       if (str == NULL) return -1;
+
+                                       /* syslog -x [str] -f [e->name] */
+                                       filesystem_copy(dst, e->name, str, 0);
+                                       free(str);
+                               }
+
+                               filesystem_unlink(e->name);
+                               store_size -= e->size;
+                               e->size = 0;
+                       }
+
+                       e = e->next;
+               }
+
+               /* if data store is over all_max, delete/archive more BB files */
+               if (store_size > all_max) debug_log(ASL_LEVEL_NOTICE, "Additional BB Scan\n");
+
+               e = bb_list;
+               while ((e != NULL) && (store_size > all_max))
+               {
+                       if (e->size != 0)
+                       {
+                               if (dst->rotate_dir != NULL)
+                               {
+                                       str = NULL;
+                                       asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+                                       if (str == NULL) return -1;
+
+                                       /* syslog -x [str] -f [e->name] */
+                                       filesystem_copy(dst, e->name, str, 0);
+                                       free(str);
+                               }
+
+                               filesystem_unlink(e->name);
+                               store_size -= e->size;
+                               e->size = 0;
+                       }
+
+                       e = e->next;
+               }
+       }
+
+       free_name_list(ymd_list);
+       free_name_list(bb_list);
+       free_name_list(aux_list);
+       free_name_list(bb_aux_list);
+
+       debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size);
+
+       return 0;
+}
+
+static asl_out_file_list_t *
+_remove_youngest_activity_tracing_file(asl_out_file_list_t *l)
+{
+       asl_out_file_list_t *f;
+
+       /* ignore youngest activity tracing file - it is the active file */
+       if (l->next == NULL)
+       {
+               debug_log(ASL_LEVEL_INFO, "    ignore youngest (only) activity tracing file %s\n", l->name);
+               asl_out_file_list_free(l);
+               return NULL;
+       }
+
+       for (f = l; f->next->next != NULL; f = f->next);
+       debug_log(ASL_LEVEL_INFO, "    ignore youngest activity tracing file %s\n", f->next->name);
+       asl_out_file_list_free(f->next);
+       f->next = NULL;
+       return l;
+}
+
+/* move sequenced source files to dst dir, renaming as we go */
+int
+module_copy_rename(asl_out_dst_data_t *dst)
+{
+       asl_out_file_list_t *src_list, *dst_list, *f;
+       char *dst_dir;
+       char fpathsrc[MAXPATHLEN], fpathdst[MAXPATHLEN];
+       uint32_t src_count, dst_count;
+       int32_t x, moved;
+
+       if (dst == NULL) return -1;
+       if (dst->path == NULL) return -1;
+
+       src_list = asl_list_src_files(dst);
+
+       /*
+        * Note: the unmarked file (e.g. system.log) is included in src_list.
+        * If it is from a MODULE_FLAG_EXTERNAL dst and it is less than 24 hours old,
+        * we ignore it.  If it is not external, we also ignore it since syslogd will
+        * checkpoint it to create system.log.Tnnnnnnnnnn.
+        */
+       if ((src_list != NULL) && (src_list->stamp == STAMP_STYLE_NULL))
+       {
+               bool ignore_it = false;
+
+               if (dst->flags & MODULE_FLAG_EXTERNAL)
+               {
+                       if ((time(NULL) - src_list->ftime) < SECONDS_PER_DAY)
+                       {
+                               debug_log(ASL_LEVEL_INFO, "    ignore src file %s since it is external and less than a day old\n", src_list->name);
+                               ignore_it = true;
+                       }
+               }
+               else
+               {
+                       debug_log(ASL_LEVEL_INFO, "    ignore src file %s since it is internal and syslogd will checkpoint it when it needs to be renamed\n", src_list->name);
+                       ignore_it = true;
+               }
+
+               if (ignore_it)
+               {
+                       asl_out_file_list_t *first = src_list;
+                       src_list = src_list->next;
+                       first->next = NULL;
+                       asl_out_file_list_free(first);
+               }
+       }
+
+       if (src_list == NULL)
+       {
+               debug_log(ASL_LEVEL_INFO, "    no src files\n");
+               return 0;
+       }
+
+       debug_log(ASL_LEVEL_INFO, "    src files\n");
+
+       src_count = 0;
+       for (f = src_list; f != NULL; f = f->next)
+       {
+               debug_log(ASL_LEVEL_INFO, "      %s\n", f->name);
+               src_count++;
+       }
+
+       dst_list = asl_list_dst_files(dst);
+
+       if ((dst_list != NULL) && (dst->flags & MODULE_FLAG_ACTIVITY))
+       {
+               dst_list = _remove_youngest_activity_tracing_file(dst_list);
+       }
+
+       dst_dir = dst->rotate_dir;
+       if (dst_dir == NULL) dst_dir = dst->dir;
+
+       dst_count = 0;
+
+       if (dst_list == NULL) debug_log(ASL_LEVEL_INFO, "    no dst files\n");
+       else debug_log(ASL_LEVEL_INFO, "    dst files\n");
+
+       for (f = dst_list; f != NULL; f = f->next)
+       {
+               debug_log(ASL_LEVEL_INFO, "      %s\n", f->name);
+               dst_count++;
+       }
+
+       if (dst->style_flags & MODULE_NAME_STYLE_STAMP_SEQ)
+       {
+               for (f = dst_list; f != NULL; f = f->next)
+               {
+                       int is_gz = 0;
+                       char *dot = strrchr(f->name, '.');
+                       if ((dot != NULL) && (!strcmp(dot, ".gz"))) is_gz = 1;
+
+                       snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst_dir, f->name);
+
+                       if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS)
+                       {
+                               snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d%s", dst_dir, dst->base, f->seq+src_count, (is_gz == 1) ? ".gz" : "");
+                       }
+                       else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES)
+                       {
+                               snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%d%s", dst_dir, dst->base, dst->ext, f->seq+src_count, (is_gz == 1) ? ".gz" : "");
+                       }
+                       else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)
+                       {
+                               snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d.%s%s", dst_dir, dst->base, f->seq+src_count, dst->ext, (is_gz == 1) ? ".gz" : "");
+                       }
+
+                       filesystem_rename(fpathsrc, fpathdst);
+               }
+
+               for (f = src_list, x = 0; f != NULL; f = f->next, x++)
+               {
+                       snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->dir, f->name);
+
+                       if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS)
+                       {
+                               snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d", dst_dir, dst->base, x);
+                       }
+                       else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES)
+                       {
+                               snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%d", dst_dir, dst->base, dst->ext, x);
+                       }
+                       else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)
+                       {
+                               snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d.%s", dst_dir, dst->base, x, dst->ext);
+                       }
+
+                       moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags);
+                       if (moved != 0)
+                       {
+                               if (dst->flags & MODULE_FLAG_TRUNCATE)
+                               {
+                                       filesystem_truncate(fpathsrc);
+                                       filesystem_reset_ctime(fpathsrc);
+                               }
+                               else
+                               {
+                                       filesystem_unlink(fpathsrc);
+                               }
+                       }
+               }
+       }
+       else
+       {
+               for (f = src_list; f != NULL; f = f->next)
+               {
+                       /* final / active base stamped file looks like a checkpointed file - ignore it */
+                       if ((dst->flags & MODULE_FLAG_BASESTAMP) && (f->next == NULL)) break;
+
+                       snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->dir, f->name);
+
+                       /* MODULE_FLAG_EXTERNAL files are not decorated with a timestamp */
+                       if (dst->flags & MODULE_FLAG_EXTERNAL)
+                       {
+                               char tstamp[32];
+
+                               asl_make_timestamp(f->ftime, dst->style_flags, tstamp, sizeof(tstamp));
+
+                               if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS)
+                               {
+                                       snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s", dst_dir, dst->base, tstamp);
+                               }
+                               else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES)
+                               {
+                                       snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%s", dst_dir, dst->base, dst->ext, tstamp);
+                               }
+                               else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)
+                               {
+                                       snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%s", dst_dir, dst->base, tstamp, dst->ext);
+                               }
+
+                       }
+                       else
+                       {
+                               snprintf(fpathdst, sizeof(fpathdst), "%s/%s", dst_dir, f->name);
+                       }
+
+                       moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags);
+                       if (moved != 0)
+                       {
+                               if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc);
+                               else filesystem_unlink(fpathsrc);
+                       }
+               }
+       }
+
+       asl_out_file_list_free(src_list);
+       asl_out_file_list_free(dst_list);
+
+       return 0;
+}
+
+/* delete expired files */
+int
+module_expire(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts)
+{
+       asl_out_file_list_t *dst_list, *f;
+       char *base, *dst_dir, fpath[MAXPATHLEN];
+       time_t now, ttl, age;
+
+       if (dst == NULL) return -1;
+       if (dst->path == NULL) return -1;
+       if (dst->ttl[LEVEL_ALL] == 0) return 0;
+
+       ttl = dst->ttl[LEVEL_ALL];
+       if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL];
+
+       now = time(NULL);
+       if (ttl > now) return 0;
+
+       base = strrchr(dst->path, '/');
+       if (base == NULL) return -1;
+
+       dst_list = asl_list_dst_files(dst);
+
+       if ((dst_list != NULL) && (dst->flags & MODULE_FLAG_ACTIVITY))
+       {
+               dst_list = _remove_youngest_activity_tracing_file(dst_list);
+       }
+
+       *base = '\0';
+
+       dst_dir = dst->rotate_dir;
+       if (dst_dir == NULL) dst_dir = dst->dir;
+
+       if (dst_list == NULL)
+       {
+               debug_log(ASL_LEVEL_INFO, "    no dst files\n");
+       }
+       else
+       {
+               debug_log(ASL_LEVEL_INFO, "    dst files\n");
+               for (f = dst_list; f != NULL; f = f->next)
+               {
+                       char tstr[150];
+                       age = now - f->ftime;
+
+                       asl_core_time_to_str(age, tstr, sizeof(tstr));
+                       debug_log(ASL_LEVEL_INFO, "      %s (age %s%s)\n", f->name, tstr, (age > ttl) ? " - expired" : "");
+               }
+       }
+
+       for (f = dst_list; f != NULL; f = f->next)
+       {
+               age = now - f->ftime;
+               if (age > ttl)
+               {
+                       snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name);
+                       filesystem_unlink(fpath);
+               }
+       }
+
+       asl_out_file_list_free(dst_list);
+
+       if (base != NULL) *base = '/';
+
+       return 0;
+}
+
+/*
+ * Check all_max size and delete files (oldest first) to stay within size limit.
+ * If query is true, then just report total size.
+ */
+int
+module_check_size(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts, bool query, size_t *msize)
+{
+       asl_out_file_list_t *dst_list, *f, *dst_end;
+       char *dst_dir, fpath[MAXPATHLEN];
+       size_t total;
+
+       size_t all_max = dst->all_max;
+       if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max;
+
+       if (dst == NULL) return -1;
+       if (dst->path == NULL) return -1;
+
+       if (all_max == 0) return 0;
+
+       dst_list = asl_list_dst_files(dst);
+
+       if ((dst_list != NULL) && (dst->flags & MODULE_FLAG_ACTIVITY))
+       {
+               dst_list = _remove_youngest_activity_tracing_file(dst_list);
+       }
+
+       if (dst_list == NULL)
+       {
+               debug_log(ASL_LEVEL_INFO, "    no dst files\n");
+               return 0;
+       }
+
+       dst_dir = dst->rotate_dir;
+       if (dst_dir == NULL) dst_dir = dst->dir;
+
+       debug_log(ASL_LEVEL_INFO, "    dst files\n");
+       dst_end = dst_list;
+       for (f = dst_list; f != NULL; f = f->next)
+       {
+               dst_end = f;
+               debug_log(ASL_LEVEL_INFO, "      %s size %lu\n", f->name, f->size);
+       }
+
+       total = 0;
+       for (f = dst_list; f != NULL; f = f->next) total += f->size;
+
+       if (!query)
+       {
+               for (f = dst_list; (total > all_max) && (f != NULL); f = f->next)
+               {
+                       snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name);
+                       filesystem_unlink(fpath);
+                       total -= f->size;
+               }
+       }
+
+       if (msize != NULL) *msize = total;
+
+       asl_out_file_list_free(dst_list);
+
+       return 0;
+}
+
+int
+process_dst(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts)
+{
+       uint32_t ttl = dst->ttl[LEVEL_ALL];
+       if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL];
+
+       size_t all_max = dst->all_max;
+       if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max;
+
+       if (dst == NULL)
+       {
+               debug_log(ASL_LEVEL_NOTICE, "NULL dst data for output rule - skipped\n");
+       }
+       else if (dst->flags & MODULE_FLAG_ROTATE)
+       {
+               debug_log(ASL_LEVEL_NOTICE, "Checking file %s\n", dst->path);
+               debug_log(ASL_LEVEL_NOTICE, "- Rename, move to destination directory, and compress as required\n");
+
+               module_copy_rename(dst);
+
+               if (ttl > 0)
+               {
+                       char tstr[150];
+
+                       asl_core_time_to_str(ttl, tstr, sizeof(tstr));
+                       debug_log(ASL_LEVEL_NOTICE, "- Check for expired files - TTL = %s\n", tstr);
+                       module_expire(dst, opts);
+               }
+
+               if (all_max > 0)
+               {
+                       debug_log(ASL_LEVEL_NOTICE, "- Check total storage used - MAX = %lu\n", all_max);
+                       module_check_size(dst, opts, false, NULL);
+               }
+       }
+       else if ((dst->flags & MODULE_FLAG_TYPE_ASL_DIR) && (ttl > 0))
+       {
+               process_asl_data_store(dst, opts);
+       }
+
+       return 0;
+}
+
+int
+process_module(asl_out_module_t *mod, asl_out_dst_data_t *opts)
+{
+       asl_out_rule_t *r;
+       uint32_t flags = 0;
+
+       if (mod == NULL) return -1;
+
+       if (opts != NULL) flags = opts->flags;
+
+       debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
+       debug_log(ASL_LEVEL_NOTICE, "Processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name);
+
+       for (r = mod->ruleset; r != NULL; r = r->next)
+       {
+               if (r->action == ACTION_OUT_DEST)
+               {
+                       if ((flags == 0) || ((flags & r->dst->flags) != 0)) process_dst(r->dst, opts);
+               }
+       }
+
+       debug_log(ASL_LEVEL_NOTICE, "Finished processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name);
+       return 0;
+}
+
+int
+cache_delete_task(bool query, size_t *size)
+{
+       dispatch_sync(work_queue, ^{
+               asl_out_module_t *mod, *m;
+               asl_out_dst_data_t opts;
+               size_t total_size = 0;
+
+               memset(&opts, 0, sizeof(opts));
+               if ((!query) && (size != NULL)) opts.all_max = *size;
+
+               debug_log(ASL_LEVEL_NOTICE, "cache_delete_process%s size %lu\n", query ? " query" : "", opts.all_max);
+
+               mod = asl_out_module_init();
+
+               for (m = mod; m != NULL; m = m->next)
+               {
+                       bool logged = false;
+                       asl_out_rule_t *r;
+
+                       for (r = m->ruleset; r != NULL; r = r->next)
+                       {
+                               if (r->action == ACTION_OUT_DEST)
+                               {
+                                       if (r->dst->flags & MODULE_FLAG_ACTIVITY)
+                                       {
+                                               if (!logged)
+                                               {
+                                                       debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
+                                                       debug_log(ASL_LEVEL_NOTICE, "Processing activity module %s\n", (m->name == NULL) ? "asl.conf" : m->name);
+                                                       logged = true;
+                                               }
+
+                                               size_t dsize = 0;
+                                               module_check_size(r->dst, &opts, false, &dsize);
+                                               total_size += dsize;
+                                       }
+                               }
+                       }
+
+                       if (logged) debug_log(ASL_LEVEL_NOTICE, "Finished processing activity module %s\n", (m->name == NULL) ? "asl.conf" : m->name);
+               }
+
+               asl_out_module_free(mod);
+
+               if (size != NULL) *size = total_size;
+       });
+
+       return 0;
+}
+
+asl_msg_list_t *
+control_query(asl_msg_t *a)
+{
+       asl_msg_list_t *out;
+       char *qstr, *str, *res;
+       uint32_t len, reslen, status;
+       uint64_t cmax, qmin;
+       kern_return_t kstatus;
+       caddr_t vmstr;
+       security_token_t sec;
+
+       if (asl_server_port == MACH_PORT_NULL)
+       {
+               kstatus = bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
+               if (asl_server_port == MACH_PORT_NULL) return NULL;
+       }
+
+       qstr = asl_msg_to_string((asl_msg_t *)a, &len);
+
+       str = NULL;
+       if (qstr == NULL)
+       {
+               asprintf(&str, "1\nQ [= ASLOption control]\n");
+       }
+       else
+       {
+               asprintf(&str, "1\n%s [= ASLOption control]\n", qstr);
+               free(qstr);
+       }
+
+       if (str == NULL) return NULL;
+
+       /* length includes trailing nul */
+       len = strlen(str) + 1;
+       out = NULL;
+       qmin = 0;
+       cmax = 0;
+       sec.val[0] = -1;
+       sec.val[1] = -1;
+
+       res = NULL;
+       reslen = 0;
+       status = ASL_STATUS_OK;
+
+       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
+       if (kstatus != KERN_SUCCESS) return NULL;
+
+       memmove(vmstr, str, len);
+       free(str);
+
+       status = 0;
+       kstatus = _asl_server_query(asl_server_port, vmstr, len, qmin, 1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec);
+       if (kstatus != KERN_SUCCESS) return NULL;
+
+       if (res == NULL) return NULL;
+
+       out = asl_msg_list_from_string(res);
+       vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
+
+       return out;
+}
+
+int
+checkpoint(const char *name)
+{
+       /* send checkpoint message to syslogd */
+       debug_log(ASL_LEVEL_NOTICE, "Checkpoint module %s\n", (name == NULL) ? "*" : name);
+       if (dryrun) return 0;
+
+       asl_msg_t *qmsg = asl_msg_new(ASL_TYPE_QUERY);
+       char *tmp = NULL;
+       asl_msg_list_t *res;
+
+       asprintf(&tmp, "%s checkpoint", (name == NULL) ? "*" : name);
+       asl_msg_set_key_val_op(qmsg, "action", tmp, ASL_QUERY_OP_EQUAL);
+       free(tmp);
+
+       res = control_query(qmsg);
+
+       asl_msg_list_release(res);
+       return 0;
+}
diff --git a/aslmanager.tproj/daemon.h b/aslmanager.tproj/daemon.h
new file mode 100644 (file)
index 0000000..ed05961
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <asl_msg_list.h>
+#include "asl_common.h"
+
+#define DEFAULT_MAX_SIZE 150000000
+#define IOBUFSIZE 4096
+
+#define DO_ASLDB       0x00000001
+#define DO_MODULE      0x00000002
+#define DO_CHECKPT     0x00000004
+
+#define DEBUG_FLAG_MASK  0xfffffff0
+#define DEBUG_LEVEL_MASK 0x0000000f
+#define DEBUG_FILE       0x00000010
+#define DEBUG_STDERR     0x00000020
+#define DEBUG_ASL        0x00000040
+
+#define AUX_URL_MINE "file:///var/log/asl/"
+#define AUX_URL_MINE_LEN 20
+
+#define SECONDS_PER_HOUR 3600
+#define SECONDS_PER_MINUTE 60
+
+/* length of "file://" */
+#define AUX_URL_PATH_OFFSET 7
+
+#define NAME_LIST_FLAG_COMPRESSED 0x00000001
+
+#define DAEMON_STATE_IDLE  0x00000000
+#define DAEMON_STATE_MAIN  0x00000001
+#define DAEMON_STATE_CACHE 0x00000002
+
+typedef struct name_list_s
+{
+       char *name;
+       size_t size;
+       uint32_t flags;
+       struct name_list_s *next;
+} name_list_t;
+
+const char *keep_str(uint8_t mask);
+void set_debug(int flag, const char *str);
+void debug_log(int level, char *str, ...);
+void debug_close();
+
+name_list_t *add_to_name_list(name_list_t *l, const char *name, size_t size, uint32_t flags);
+void free_name_list(name_list_t *l);
+
+int copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst);
+
+void filesystem_rename(const char *src, const char *dst);
+void filesystem_unlink(const char *path);
+void filesystem_truncate(const char *path);
+void filesystem_rmdir(const char *path);
+int32_t filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags);
+int32_t filesystem_reset_ctime(const char *path);
+
+int remove_directory(const char *path);
+size_t directory_size(const char *path);
+
+time_t parse_ymd_name(const char *name);
+uint32_t ymd_file_age(const char *name, time_t now, uid_t *u, gid_t *g);
+uint32_t ymd_file_filter(const char *name, const char *path, uint32_t keep_mask, mode_t ymd_mode, uid_t ymd_uid, gid_t ymd_gid);
+
+int process_asl_data_store(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts);
+int module_copy_rename(asl_out_dst_data_t *dst);
+int module_expire(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts);
+int module_check_size(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts, bool check, size_t *msize);
+int process_module(asl_out_module_t *mod, asl_out_dst_data_t *opts);
+int process_dst(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts);
+
+asl_msg_list_t * control_query(asl_msg_t *a);
+int checkpoint(const char *name);
+
+int cache_delete_task(bool query, size_t *size);
+void main_task(void);
+
index 1cc2662d55dc5cb998cd4da3374fc43c71be62d0..218e42e88dcb96c89bfa37f5ec9c3fb1e6683c82 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2004-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -31,7 +31,7 @@
 #include <Availability.h>
 
 /* Version number encodes the date YYYYMMDD */
 #include <Availability.h>
 
 /* Version number encodes the date YYYYMMDD */
-#define ASL_API_VERSION 20131108
+#define ASL_API_VERSION 20150225
 
 typedef struct __asl_object_s *asl_object_t;
 typedef asl_object_t aslclient;
 
 typedef struct __asl_object_s *asl_object_t;
 typedef asl_object_t aslclient;
@@ -902,7 +902,7 @@ asl_object_t asl_open_from_file(int descriptor, const char *ident, const char *f
  * similarly must still be freed by the caller by calling asl_free() if the
  * caller loses reference to it.  Any changes made to it after calling
  * asl_log_descriptor() are not applicable to the message used. descriptor
  * similarly must still be freed by the caller by calling asl_free() if the
  * caller loses reference to it.  Any changes made to it after calling
  * asl_log_descriptor() are not applicable to the message used. descriptor
- * is treated differentlty based on the value of fd_type.
+ * is treated differently based on the value of fd_type.
  *
  * If fd_type is ASL_LOG_DESCRIPTOR_READ, the descriptor must be open for read
  * access.  ASL uses GCD to read from the descriptor as data becomes available.
  *
  * If fd_type is ASL_LOG_DESCRIPTOR_READ, the descriptor must be open for read
  * access.  ASL uses GCD to read from the descriptor as data becomes available.
index e0383aa3d0c304b83c975ab8365f34bd5ab64c29..060fe4e122d7d4cdd451dc13fe2596a5f593d229 100644 (file)
@@ -96,6 +96,9 @@ ASL_STATUS asl_client_send(asl_client_t *client, asl_msg_t *msg) __OSX_AVAILABLE
 asl_msg_list_t *asl_client_search(asl_client_t *client, asl_msg_t *query) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 asl_msg_list_t *asl_client_match(asl_client_t *client, asl_msg_list_t *querylist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 
 asl_msg_list_t *asl_client_search(asl_client_t *client, asl_msg_t *query) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 asl_msg_list_t *asl_client_match(asl_client_t *client, asl_msg_list_t *querylist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 
+uint32_t asl_client_set_control(asl_client_t *client, uint32_t filter) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0);
+uint32_t asl_client_get_control(asl_client_t *client) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0);
+
 __END_DECLS
 
 #endif /* __ASL_CLIENT_H__ */
 __END_DECLS
 
 #endif /* __ASL_CLIENT_H__ */
index 3b29a4a606b6239debe43a201e65165db9d90503..f9338721dafee3da80de7bd44c0a5f020fe13ffc 100644 (file)
 #include <time.h>
 #include <mach/mach.h>
 #include <Availability.h>
 #include <time.h>
 #include <mach/mach.h>
 #include <Availability.h>
+#include <TargetConditionals.h>
+
+#define streq(A, B) (strcmp(A, B) == 0)
+#define strneq(A, B) (strcmp(A, B) != 0)
+
+#define streq_len(A, B, C) (strncmp(A, B, C) == 0)
+#define strneq_len(A, B, C) (strncmp(A, B, C) != 0)
+
+#define strcaseeq(A, B) (strcasecmp(A, B) == 0)
+#define strcaseneq(A, B) (strcasecmp(A, B) != 0)
+
+#define strcaseeq_len(A, B, C) (strncasecmp(A, B, C) == 0)
+#define strcaseneq_len(A, B, C) (strcasecmp(A, B, C) != 0)
 
 typedef uint32_t ASL_STATUS;
 
 
 typedef uint32_t ASL_STATUS;
 
@@ -84,8 +97,13 @@ typedef uint32_t ASL_STATUS;
 #define ASL_PLACE_DATABASE 0
 #define ASL_PLACE_ARCHIVE 1
 
 #define ASL_PLACE_DATABASE 0
 #define ASL_PLACE_ARCHIVE 1
 
+#if TARGET_OS_SIMULATOR
+#define ASL_PLACE_DATABASE_DEFAULT asl_filesystem_path(ASL_PLACE_DATABASE)
+#define ASL_PLACE_ARCHIVE_DEFAULT asl_filesystem_path(ASL_PLACE_ARCHIVE)
+#else
 #define ASL_PLACE_DATABASE_DEFAULT "/var/log/asl"
 #define ASL_PLACE_ARCHIVE_DEFAULT "/var/log/asl.archive"
 #define ASL_PLACE_DATABASE_DEFAULT "/var/log/asl"
 #define ASL_PLACE_ARCHIVE_DEFAULT "/var/log/asl.archive"
+#endif
 
 mach_port_t asl_core_get_service_port(int reset) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 
 
 mach_port_t asl_core_get_service_port(int reset) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 
@@ -100,6 +118,9 @@ char *asl_core_encode_buffer(const char *in, uint32_t len) __OSX_AVAILABLE_START
 int32_t asl_core_decode_buffer(const char *in, char **buf, uint32_t *len) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
 
 time_t asl_core_parse_time(const char *in, uint32_t *tlen) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 int32_t asl_core_decode_buffer(const char *in, char **buf, uint32_t *len) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
 
 time_t asl_core_parse_time(const char *in, uint32_t *tlen) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
+size_t asl_core_str_to_size(char *s) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); //TODO: 10_11 & 7_1 or 8_0
+time_t asl_core_str_to_time(char *s, uint32_t def_n) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); //TODO: 10_11 & 7_1 or 8_0
+void asl_core_time_to_str(time_t s, char *str, size_t len) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); //TODO: 10_11 & 7_1 or 8_0
 
 const char *asl_filesystem_path(uint32_t place) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 
 
 const char *asl_filesystem_path(uint32_t place) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 
index e3d38ab209adba202e0d22d8be71336f56bfdbe7..07a2a2b377bd2f45e252e2e1e2d57fe4cc134277 100644 (file)
 #define ASL_FILE_FILTER_FLAG_KEEP_MATCHES 0x00000001
 
 /* NB CACHE_SIZE must be > 1 */
 #define ASL_FILE_FILTER_FLAG_KEEP_MATCHES 0x00000001
 
 /* NB CACHE_SIZE must be > 1 */
-#define CACHE_SIZE 256
+#define CACHE_SIZE 128
+
+/* This makes the maximum size of a file_string_t 128 bytes */
+#define CACHE_MAX_STRING_LEN 108
 
 /* Size of the fixed-length part of a MSG record */
 #define MSG_RECORD_FIXED_LENGTH 122
 
 /* Size of the fixed-length part of a MSG record */
 #define MSG_RECORD_FIXED_LENGTH 122
@@ -101,7 +104,7 @@ typedef struct file_string_s
        uint64_t where;
        uint32_t hash;
        struct file_string_s *next;
        uint64_t where;
        uint32_t hash;
        struct file_string_s *next;
-       char str[];
+       char str[CACHE_MAX_STRING_LEN];
 } file_string_t;
 
 typedef struct asl_file_s
 } file_string_t;
 
 typedef struct asl_file_s
@@ -113,8 +116,10 @@ typedef struct asl_file_s
        uint32_t string_cache_count;
        uint32_t msg_count;
        file_string_t *string_list;
        uint32_t string_cache_count;
        uint32_t msg_count;
        file_string_t *string_list;
+       file_string_t *string_spare;
        uint64_t first;
        uint64_t last;
        uint64_t first;
        uint64_t last;
+       uint64_t last_mid;
        uint64_t prev;
        uint64_t cursor;
        uint64_t cursor_xid;
        uint64_t prev;
        uint64_t cursor;
        uint64_t cursor_xid;
index 104cd9d356ef8a909ff5e8033e902103259aa129..a346ec63af21972608a61a71ae16dbe5dd74f13d 100644 (file)
 #define __ASL_MSG_H__
 
 #include <stdint.h>
 #define __ASL_MSG_H__
 
 #include <stdint.h>
+#include <xpc/xpc.h>
+#include <asl.h>
 #include <asl_string.h>
 #include <asl_core.h>
 #include <asl_object.h>
 
 #define IndexNull ((uint32_t)-1)
 
 #include <asl_string.h>
 #include <asl_core.h>
 #include <asl_object.h>
 
 #define IndexNull ((uint32_t)-1)
 
-#define ASL_MSG_PAGE_DATA_SIZE 830
-#define ASL_MSG_PAGE_SLOTS 25
+#define ASL_MSG_PAGE_DATA_SIZE 220
+
+#define ASL_MSG_KVO_COUNT 30
+// ASL_MSG_KVO_QUERY_SLOTS = ASL_MSG_KVO_COUNT / 3;
+#define ASL_MSG_KVO_QUERY_SLOTS 10
+// ASL_MSG_KVO_MSG_SLOTS = ASL_MSG_KVO_COUNT / 2;
+#define ASL_MSG_KVO_MSG_SLOTS 15
 
 #define ASL_MSG_OFFSET_MASK   0x3fff
 #define ASL_MSG_KV_MASK       0xc000
 
 #define ASL_MSG_OFFSET_MASK   0x3fff
 #define ASL_MSG_KV_MASK       0xc000
@@ -90,9 +97,10 @@ typedef struct asl_msg_s
        uint32_t data_size;
        uint64_t mem_size;
        struct asl_msg_s *next;
        uint32_t data_size;
        uint64_t mem_size;
        struct asl_msg_s *next;
-       uint16_t key[ASL_MSG_PAGE_SLOTS];
-       uint16_t val[ASL_MSG_PAGE_SLOTS];
-       uint16_t op[ASL_MSG_PAGE_SLOTS];
+#ifndef __LP64__
+       uint32_t pad;
+#endif
+       uint16_t kvo[ASL_MSG_KVO_COUNT];
        char data[ASL_MSG_PAGE_DATA_SIZE];
 } asl_msg_t;
 
        char data[ASL_MSG_PAGE_DATA_SIZE];
 } asl_msg_t;
 
@@ -130,6 +138,8 @@ asl_string_t * asl_string_append_asl_msg(asl_string_t *str, asl_msg_t *msg) __OS
 
 int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 
 
 int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 
+void _asl_log_args_to_xpc(asl_object_t client, asl_object_t msg, xpc_object_t dict); //TODO: ADD AVAILABLITY INFO
+
 __END_DECLS
 
 #endif /* __ASL_MSG_H__ */
 __END_DECLS
 
 #endif /* __ASL_MSG_H__ */
index dcac0a40d27e438959fbf4d5cd1868ce634f514f..03cf96c73d19dbe9b21822b96f2ec698826fd89b 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_LICENSE_HEADER_START@
  *
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/time.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/time.h>
+#include <mach/vm_statistics.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <Availability.h>
 #include <os/object.h>
 #include <os/object_private.h>
 
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <Availability.h>
 #include <os/object.h>
 #include <os/object_private.h>
 
-#define streq(A, B) (strcmp(A, B) == 0)
-#define strcaseeq(A, B) (strcasecmp(A, B) == 0)
-
 #define ASL_QUERY_OP_NULL          0x00000
 
 #define ASLMANAGER_SERVICE_NAME "com.apple.aslmanager"
 #define ASL_QUERY_OP_NULL          0x00000
 
 #define ASLMANAGER_SERVICE_NAME "com.apple.aslmanager"
 /* File and Store Open Option */
 #define ASL_OPT_OPEN_READ   0x80000000
 
 /* File and Store Open Option */
 #define ASL_OPT_OPEN_READ   0x80000000
 
+#define ASL_OPT_SHIM_NO_ASL   0x10000000
+#define ASL_OPT_SHIM_NO_TRACE 0x20000000
+
 #define ASL_STORE_LOCATION_FILE 0
 #define ASL_STORE_LOCATION_MEMORY 1
 
 #define ASL_OPT_SYSLOG_LEGACY  0x00010000
 
 #define ASL_KEY_FREE_NOTE "ASLFreeNotify"
 #define ASL_STORE_LOCATION_FILE 0
 #define ASL_STORE_LOCATION_MEMORY 1
 
 #define ASL_OPT_SYSLOG_LEGACY  0x00010000
 
 #define ASL_KEY_FREE_NOTE "ASLFreeNotify"
+#define ASL_KEY_MESSAGETRACER "com.apple.message.domain"
+
+/* remote control bits */
+#define EVAL_LEVEL_MASK   0x000000ff
+#define EVAL_ACTION_MASK  0xffff0000
+#define EVAL_ACTIVE       0x00010000
+#define EVAL_SEND_ASL     0x00020000
+#define EVAL_SEND_TRACE   0x00040000
+#define EVAL_TEXT_FILE    0x00080000
+#define EVAL_ASL_FILE     0x00100000
+#define EVAL_TUNNEL       0x00200000
+#define EVAL_QUOTA        0x00400000
 
 /*
  * Private types
 
 /*
  * Private types
 
 #define NOQUOTA_FILE_PATH "/etc/asl/.noquota"
 
 
 #define NOQUOTA_FILE_PATH "/etc/asl/.noquota"
 
+// TODO: this could move to vm_statistics.h
+#ifndef VM_MEMORY_ASL
+#define VM_MEMORY_ASL (VM_MEMORY_APPLICATION_SPECIFIC_1 + 7)
+#endif
+
+/*
+ * Memory limits: work queue size for syslogd and max message size in libasl
+ */
+#if TARGET_OS_EMBEDDED
+#define SYSLOGD_WORK_QUEUE_MEMORY 3072000
+#define LIBASL_MAX_MSG_SIZE       2048000
+#else
+#define SYSLOGD_WORK_QUEUE_MEMORY 10240000
+#define LIBASL_MAX_MSG_SIZE        8192000
+#endif
+
 __BEGIN_DECLS
 
 int asl_store_location() __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
 __BEGIN_DECLS
 
 int asl_store_location() __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
@@ -80,6 +109,8 @@ int asl_syslog_faciliy_name_to_num(const char *name) __OSX_AVAILABLE_STARTING(__
 const char *asl_syslog_faciliy_num_to_name(int n) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
 int asl_trigger_aslmanager(void) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 int asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *active) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
 const char *asl_syslog_faciliy_num_to_name(int n) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
 int asl_trigger_aslmanager(void) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
 int asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *active) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
+uint32_t asl_set_local_control(asl_object_t client, uint32_t filter) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0);
+uint32_t asl_get_local_control(asl_object_t client) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0);
 
 /* EXCLUSIVLY FOR USE BY DEV TOOLS */
 /* DO NOT USE THIS INTERFACE OTHERWISE */
 
 /* EXCLUSIVLY FOR USE BY DEV TOOLS */
 /* DO NOT USE THIS INTERFACE OTHERWISE */
index f2fdda03f4f298f5f76a242ded4e1f1f7e0d8055..106aa9016196062a2699ec2dd06a47a2264479f7 100644 (file)
@@ -490,7 +490,7 @@ except that it takes a va_list argument.
 .Fc
 is similar to
 .Fn asl_log ,
 .Fc
 is similar to
 .Fn asl_log ,
-except the value for ASL_KEY_MESSAGE is taken from
+except the value for ASL_KEY_MSG is taken from
 .Ar msg
 rather than being constructed using a
 .Fn printf
 .Ar msg
 rather than being constructed using a
 .Fn printf
index 745a788d6b9a0e47da167cb1e2f239f3d0a6c578..8e268db107ba8eeebaf745b4574f9ee355afb580 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2004-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -52,6 +52,8 @@
 #include <dispatch/dispatch.h>
 #include <libkern/OSAtomic.h>
 #include <os/activity.h>
 #include <dispatch/dispatch.h>
 #include <libkern/OSAtomic.h>
 #include <os/activity.h>
+#include <os/trace.h>
+#include <os/log_private.h>
 #include <asl_ipc.h>
 #include <asl_client.h>
 #include <asl_core.h>
 #include <asl_ipc.h>
 #include <asl_client.h>
 #include <asl_core.h>
 
 #define FETCH_BATCH    256
 
 
 #define FETCH_BATCH    256
 
-#define LEVEL_MASK   0x0000000f
-#define EVAL_MASK    0x000000f0
-#define EVAL_IGNORE  0x00000000
-#define EVAL_ASLFILE 0x00000010
-#define EVAL_SEND    0x00000020
-#define EVAL_TUNNEL  0x00000040
-#define EVAL_FILE    0x00000080
-#define EVAL_QUOTA   0x00000100
+#define EVAL_DEFAULT_ACTION (EVAL_SEND_ASL | EVAL_SEND_TRACE)
+#define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE)
 
 /*
  * Clients get a max of 36000 messages per hour.
 
 /*
  * Clients get a max of 36000 messages per hour.
 #define NOQUOTA_ENV "ASL_QUOTA_DISABLED"
 #define QUOTA_DISABLED_MSG "*** MESSAGE QUOTA DISABLED FOR THIS PROCESS ***"
 #define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***"
 #define NOQUOTA_ENV "ASL_QUOTA_DISABLED"
 #define QUOTA_DISABLED_MSG "*** MESSAGE QUOTA DISABLED FOR THIS PROCESS ***"
 #define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***"
-#define QUOTA_LEVEL 2
-#define QUOTA_LEVEL_STR "2"
+#define QUOTA_LEVEL ASL_LEVEL_CRIT
+#define QUOTA_LEVEL_STR ASL_STRING_CRIT
+
+/*
+ * Limit the size of messages sent to syslogd.
+ */
+#define SIZE_LIMIT_MSG "*** ASL MESSAGE SIZE (%u bytes) EXCEEDED MAXIMIMUM SIZE (%u bytes) ***"
+
+static const uint8_t shim_asl_to_trace_type[8] = {
+       OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, // Emergency, Alert, Critical
+       OS_TRACE_TYPE_ERROR, // Error
+       OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, // Warning, Notice, Info
+       OS_TRACE_TYPE_DEBUG // Debug
+};
+
 
 /* forward */
 static ASL_STATUS _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring);
 
 /* forward */
 static ASL_STATUS _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring);
@@ -428,13 +437,14 @@ asl_set_filter(asl_object_t client, int f)
 
 /*
  * Evaluate client / message / level to determine what to do with a message.
 
 /*
  * Evaluate client / message / level to determine what to do with a message.
- * Checks filters, tunneling, and log files.  Returns EVAL_IGNORE if the message
- * can be ignored.  Otherwise it returns the bits below, ORed with the level.
+ * Checks filters, tunneling, and log files.
+ * Returns the bits below, ORed with the message level.
  *
  *
- * EVAL_ASLFILE - will write to an asl file (see asl_open_from_file)
- * EVAL_SEND - will send to syslogd
- * EVAL_TUNNEL - will send to syslogd with tunneling enabled
- * EVAL_FILE - will write to file
+ * EVAL_SEND_ASL       - send this message to syslogd
+ * EVAL_SEND_TRACE     - log this message with Activity Tracing
+ * EVAL_ASL_FILE       - write to a standalone ASL file (see asl_open_from_file)
+ * EVAL_TEXT_FILE      - write this message to a text file / stderr
+ * EVAL_TUNNEL         - tunneling enabled when sending to syslogd
  */
 uint32_t
 _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel)
  */
 uint32_t
 _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel)
@@ -445,37 +455,45 @@ _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel)
        int check;
        uint64_t v64;
        const char *val;
        int check;
        uint64_t v64;
        const char *val;
+       uint32_t eval;
 
        level = ASL_LEVEL_DEBUG;
        if (slevel >= 0) level = slevel;
 
        level = ASL_LEVEL_DEBUG;
        if (slevel >= 0) level = slevel;
-       
+
        val = NULL;
        if ((asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL) == 0) && (val != NULL)) level = atoi(val);
        val = NULL;
        if ((asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL) == 0) && (val != NULL)) level = atoi(val);
-       
+
        if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
        else if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
 
        if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT))
        {
                /* sending to something other than a client */
        if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
        else if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
 
        if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT))
        {
                /* sending to something other than a client */
-               return (level | EVAL_SEND);
+               return EVAL_ACTIVE | EVAL_SEND_ASL | level;
        }
 
        asl = (asl_client_t *)client;
        }
 
        asl = (asl_client_t *)client;
+       if ((asl != NULL) && (asl->aslfile != NULL)) return (EVAL_ASL_FILE | level);
+
+       if (asl == NULL) asl = _asl_open_default();
        if (asl == NULL)
        {
        if (asl == NULL)
        {
-               asl = _asl_open_default();
-               if (asl == NULL) return EVAL_IGNORE;
+               eval = EVAL_ACTIVE | EVAL_DEFAULT_ACTION | level;
+               eval &= ~EVAL_SEND_ASL;
+               return eval;
        }
 
        }
 
-       if (asl->aslfile != NULL) return (level | EVAL_ASLFILE);
-
-       lmask = ASL_FILTER_MASK(level);
+       eval = (asl_client_get_control(asl) & EVAL_ACTION_MASK) | level;
 
        filter = asl->filter & 0xff;
        tunnel = (asl->filter & ASL_FILTER_MASK_TUNNEL) >> 8;
 
        filter = asl->filter & 0xff;
        tunnel = (asl->filter & ASL_FILTER_MASK_TUNNEL) >> 8;
+       if (tunnel != 0) eval |= EVAL_TUNNEL;
+
+       /* don't send MessageTracer messages to Activity Tracing */
+       val = NULL;
+       if ((asl_msg_lookup(msg, ASL_KEY_MESSAGETRACER, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
 
 
-       if (!(asl->options & ASL_OPT_NO_REMOTE))
+       if ((asl->options & ASL_OPT_NO_REMOTE) == 0)
        {
                pthread_mutex_lock(&_asl_global.lock);
 
        {
                pthread_mutex_lock(&_asl_global.lock);
 
@@ -502,39 +520,34 @@ _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel)
                        }
                }
 
                        }
                }
 
-               pthread_mutex_unlock(&_asl_global.lock);
-               /* master filter overrides local filter */
-               if (_asl_global.master_filter != 0)
+               if (_asl_global.master_filter & EVAL_ACTIVE)
                {
                {
-                       filter = _asl_global.master_filter;
-                       tunnel = 1;
-               }
+                       /* clear bits and set according to master */
+                       eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE);
+                       eval |= (_asl_global.master_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE));
+                       eval |= EVAL_TUNNEL;
 
 
-               /* process-specific filter overrides local and master */
-               if (_asl_global.proc_filter != 0)
-               {
-                       filter = _asl_global.proc_filter;
-                       tunnel = 1;
+                       if ((_asl_global.master_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
                }
                }
-       }
 
 
-       if ((filter != 0) && ((filter & lmask) != 0))
-       {
-               level |= EVAL_SEND;
-               if (tunnel != 0) level |= EVAL_TUNNEL;
-               if (asl->out_count > 0) level |= EVAL_FILE;
+               if (_asl_global.proc_filter & EVAL_ACTIVE)
+               {
+                       /* clear bits and set according to proc */
+                       eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE);
+                       eval |= (_asl_global.proc_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE));
+                       eval |= EVAL_TUNNEL;
 
 
-               return level;
-       }
+                       if ((_asl_global.proc_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
+               }
 
 
-       if ((asl->options & ASL_OPT_SYSLOG_LEGACY) && (filter != 0) && ((filter & lmask) == 0))
-       {
-               return EVAL_IGNORE;
+               pthread_mutex_unlock(&_asl_global.lock);
        }
 
        }
 
-       if (asl->out_count > 0) return (level | EVAL_FILE);
+       lmask = ASL_FILTER_MASK(level);
+       if ((filter != 0) && ((filter & lmask) == 0)) eval &= ~EVAL_SEND_ASL;
+       if (asl->out_count > 0) eval |= EVAL_TEXT_FILE;
 
 
-       return EVAL_IGNORE;
+       return eval;
 }
 
 /*
 }
 
 /*
@@ -546,7 +559,7 @@ _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel)
  * ap: va_list for the format
  * returns 0 for success, non-zero for failure
  */
  * ap: va_list for the format
  * returns 0 for success, non-zero for failure
  */
-static ASL_STATUS
+__private_extern__ ASL_STATUS
 _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
 {
        int saved_errno = errno;
 _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
 {
        int saved_errno = errno;
@@ -588,11 +601,7 @@ _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *for
        if (expand != 0)
        {
                fmt = malloc(len + 1);
        if (expand != 0)
        {
                fmt = malloc(len + 1);
-               if (fmt == NULL)
-               {
-                       if (estr != NULL) free(estr);
-                       return ASL_STATUS_NO_MEMORY;
-               }
+               if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
 
                len = 0;
 
 
                len = 0;
 
@@ -645,16 +654,38 @@ _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *for
 int
 asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, va_list ap)
 {
 int
 asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, va_list ap)
 {
+       ASL_STATUS status = ASL_STATUS_OK;
        uint32_t eval = _asl_evaluate_send(client, msg, level);
        uint32_t eval = _asl_evaluate_send(client, msg, level);
-       if (eval == EVAL_IGNORE) return 0;
 
 
-       ASL_STATUS status = _asl_lib_vlog(client, eval, msg, format, ap);
+       if (eval & EVAL_SEND_TRACE)
+       {
+               va_list ap_copy;
+               if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
+               if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
+               uint8_t trace_type = shim_asl_to_trace_type[level];
+
+               va_copy(ap_copy, ap);
+               os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap_copy, ^(xpc_object_t xdict) {_asl_log_args_to_xpc(client, msg, xdict);} );
+               va_end(ap_copy);
+       }
+
+       if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
+       {
+               asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG);
+               if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1");
+               smsg = asl_msg_merge(smsg, (asl_msg_t *)msg);
+
+               status = _asl_lib_vlog(client, eval, (asl_object_t)smsg, format, ap);
+
+               asl_msg_release(smsg);
+       }
+
        return (status == ASL_STATUS_OK) ? 0 : -1;
 }
 
 /*
  * _asl_lib_log
        return (status == ASL_STATUS_OK) ? 0 : -1;
 }
 
 /*
  * _asl_lib_log
- * SPI used by ASL_PREFILTER_LOG. Converts format arguments to a va_list and
+ * SPI used by legacy (non-shim) ASL_PREFILTER_LOG. Converts format arguments to a va_list and
  * forwards the call to _asl_lib_vlog.
  * msg:  an asl message
  * eval: log level and send flags for the message
  * forwards the call to _asl_lib_vlog.
  * msg:  an asl message
  * eval: log level and send flags for the message
@@ -665,13 +696,16 @@ asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, v
 int
 _asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *format, ...)
 {
 int
 _asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *format, ...)
 {
-       int status;
-       if (eval == EVAL_IGNORE) return 0;
+       int status = 0;
 
 
-       va_list ap;
-       va_start(ap, format);
-       status = _asl_lib_vlog(client, eval, msg, format, ap);
-       va_end(ap);
+       if (eval & EVAL_ASL)
+       {
+               va_list ap;
+
+               va_start(ap, format);
+               status = _asl_lib_vlog(client, eval, msg, format, ap);
+               va_end(ap);
+       }
 
        return status;
 }
 
        return status;
 }
@@ -688,14 +722,34 @@ _asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *f
 int
 asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ...)
 {
 int
 asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ...)
 {
-       ASL_STATUS status;
+       ASL_STATUS status = ASL_STATUS_OK;
        uint32_t eval = _asl_evaluate_send(client, msg, level);
        uint32_t eval = _asl_evaluate_send(client, msg, level);
-       if (eval == EVAL_IGNORE) return 0;
 
 
-       va_list ap;
-       va_start(ap, format);
-       status = _asl_lib_vlog(client, eval, msg, format, ap);
-       va_end(ap);
+       if (eval & EVAL_SEND_TRACE)
+       {
+               va_list ap;
+               if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
+               if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
+               uint8_t trace_type = shim_asl_to_trace_type[level];
+
+               va_start(ap, format);
+               os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap, ^(xpc_object_t xdict) {_asl_log_args_to_xpc(client, msg, xdict);} );
+               va_end(ap);
+       }
+
+       if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
+       {
+               va_list ap;
+               asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG);
+               if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1");
+               smsg = asl_msg_merge(smsg, (asl_msg_t *)msg);
+
+               va_start(ap, format);
+               status = _asl_lib_vlog(client, eval, (asl_object_t)smsg, format, ap);
+               va_end(ap);
+
+               asl_msg_release(smsg);
+       }
 
        return (status == ASL_STATUS_OK) ? 0 : -1;
 }
 
        return (status == ASL_STATUS_OK) ? 0 : -1;
 }
@@ -711,14 +765,33 @@ asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ..
 int
 asl_log_message(int level, const char *format, ...)
 {
 int
 asl_log_message(int level, const char *format, ...)
 {
-       int status;
+       ASL_STATUS status = ASL_STATUS_OK;
        uint32_t eval = _asl_evaluate_send(NULL, NULL, level);
        uint32_t eval = _asl_evaluate_send(NULL, NULL, level);
-       if (eval == EVAL_IGNORE) return 0;
 
 
-       va_list ap;
-       va_start(ap, format);
-       status = _asl_lib_vlog(NULL, eval, NULL, format, ap);
-       va_end(ap);
+       if (eval & EVAL_SEND_TRACE)
+       {
+               va_list ap;
+               if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
+               if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
+               uint8_t trace_type = shim_asl_to_trace_type[level];
+
+               va_start(ap, format);
+               os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap, NULL);
+               va_end(ap);
+       }
+
+       if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
+       {
+               va_list ap;
+               asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG);
+               if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1");
+
+               va_start(ap, format);
+               status = _asl_lib_vlog(NULL, eval, (asl_object_t)smsg, format, ap);
+               va_end(ap);
+
+               asl_msg_release(smsg);
+       }
 
        return (status == ASL_STATUS_OK) ? 0 : -1;
 }
 
        return (status == ASL_STATUS_OK) ? 0 : -1;
 }
@@ -746,7 +819,7 @@ asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *a
 
        asl = (asl_client_t *)client;
        if (asl == NULL) asl = asl_default;
 
        asl = (asl_client_t *)client;
        if (asl == NULL) asl = asl_default;
-       if (asl != NULL) l = asl->filter & 0xff;
+       if (asl != NULL) l = asl->filter & EVAL_LEVEL_MASK;
 
        if ((asl_default != NULL) && (!(asl_default->options & ASL_OPT_NO_REMOTE)))
        {
 
        if ((asl_default != NULL) && (!(asl_default->options & ASL_OPT_NO_REMOTE)))
        {
@@ -792,15 +865,43 @@ asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *a
        return 0;
 }
 
        return 0;
 }
 
+/* SPI for SHIM control */
+uint32_t
+asl_set_local_control(asl_object_t client, uint32_t filter)
+{
+       asl_client_t *asl = (asl_client_t *)client;
+       if (asl == NULL)
+       {
+               asl = _asl_open_default();
+               if (asl == NULL) return UINT32_MAX;
+       }
+       else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
+
+       return asl_client_set_control(asl, filter);
+}
+
+uint32_t
+asl_get_local_control(asl_object_t client)
+{
+       asl_client_t *asl = (asl_client_t *)client;
+       if (asl == NULL)
+       {
+               asl = _asl_open_default();
+               if (asl == NULL) return UINT32_MAX;
+       }
+       else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
+
+       return asl_client_get_control(asl);
+}
+
 /*
 /*
- * Sets Host, PID, UID, GID, and OSActivityID values in a new message.
+ * Sets PID and OSActivityID values in a new message.
  * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided.
  */
 asl_msg_t *
 asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr)
 {
        char aux_val[64];
  * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided.
  */
 asl_msg_t *
 asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr)
 {
        char aux_val[64];
-       char aux_host[_POSIX_HOST_NAME_MAX];
        asl_msg_t *aux;
        int status;
        unsigned int osacount = 1;
        asl_msg_t *aux;
        int status;
        unsigned int osacount = 1;
@@ -815,7 +916,7 @@ asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const
        /* Time and TimeNanoSec */
        if (tv != NULL)
        {
        /* Time and TimeNanoSec */
        if (tv != NULL)
        {
-               snprintf(aux_val, sizeof(aux_val), "%lu", tv->tv_sec);
+               snprintf(aux_val, sizeof(aux_val), "%llu", (unsigned long long) tv->tv_sec);
                asl_msg_set_key_val(aux, ASL_KEY_TIME, aux_val);
 
                snprintf(aux_val, sizeof(aux_val), "%d", tv->tv_usec * 1000);
                asl_msg_set_key_val(aux, ASL_KEY_TIME, aux_val);
 
                snprintf(aux_val, sizeof(aux_val), "%d", tv->tv_usec * 1000);
@@ -825,22 +926,10 @@ asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const
        /* Message */
        if (mstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_MSG, mstr);
 
        /* Message */
        if (mstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_MSG, mstr);
 
-       /* Host */
-       memset(&aux_host, 0, _POSIX_HOST_NAME_MAX);
-       if (gethostname(aux_host, _POSIX_HOST_NAME_MAX) == 0) asl_msg_set_key_val(aux, ASL_KEY_HOST, aux_host);
-
        /* PID */
        snprintf(aux_val, sizeof(aux_val), "%u", getpid());
        asl_msg_set_key_val(aux, ASL_KEY_PID, aux_val);
 
        /* PID */
        snprintf(aux_val, sizeof(aux_val), "%u", getpid());
        asl_msg_set_key_val(aux, ASL_KEY_PID, aux_val);
 
-       /* UID */
-       snprintf(aux_val, sizeof(aux_val), "%d", getuid());
-       asl_msg_set_key_val(aux, ASL_KEY_UID, aux_val);
-
-       /* GID */
-       snprintf(aux_val, sizeof(aux_val), "%d", getgid());
-       asl_msg_set_key_val(aux, ASL_KEY_GID, aux_val);
-
        /* OSActivityID */
        if (os_activity_get_active(&osaid, &osacount) == 1)
        {
        /* OSActivityID */
        if (os_activity_get_active(&osaid, &osacount) == 1)
        {
@@ -849,7 +938,7 @@ asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const
        }
 
        /* Sender */
        }
 
        /* Sender */
-       if (sstr == NULL)
+       if ((sstr == NULL) && (asl != NULL))
        {
                /* See if the client has a value for ASL_KEY_SENDER */
                status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_SENDER, &sstr, NULL);
        {
                /* See if the client has a value for ASL_KEY_SENDER */
                status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_SENDER, &sstr, NULL);
@@ -883,7 +972,7 @@ asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const
        if (sstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, sstr);
 
        /* Facility */
        if (sstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, sstr);
 
        /* Facility */
-       if (fstr == NULL)
+       if ((fstr == NULL) && (asl != NULL))
        {
                status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_FACILITY, &fstr, NULL);
                if (status != 0) fstr = NULL;
        {
                status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_FACILITY, &fstr, NULL);
                if (status != 0) fstr = NULL;
@@ -944,6 +1033,29 @@ asl_prepared_message(asl_client_t *asl, asl_msg_t *msg)
 }
 #endif
 
 }
 #endif
 
+static void
+_asl_set_option(asl_msg_t *msg, const char *opt)
+{
+       const char *val = NULL;
+       uint32_t status;
+
+       if (msg == NULL) return;
+       if (opt == NULL) return;
+
+       status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL);
+       if ((status != 0) || (val == NULL))
+       {
+               asl_msg_set_key_val(msg, ASL_KEY_OPTION, opt);
+       }
+       else
+       {
+               char *option = NULL;
+               asprintf(&option, "%s %s", opt, val);
+               asl_msg_set_key_val(msg, ASL_KEY_OPTION, option);
+               free(option);
+       }
+}
+
 static ASL_STATUS
 _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr)
 {
 static ASL_STATUS
 _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr)
 {
@@ -958,7 +1070,7 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m
        asl_client_t *asl = NULL;
        static dispatch_once_t noquota_once;
 
        asl_client_t *asl = NULL;
        static dispatch_once_t noquota_once;
 
-       if (eval == EVAL_IGNORE) return ASL_STATUS_OK;
+       if ((eval & EVAL_ASL) == 0) return ASL_STATUS_OK;
 
        if (obj == NULL)
        {
 
        if (obj == NULL)
        {
@@ -971,12 +1083,10 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m
        {
                objtype = asl_get_type(obj);
                if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
        {
                objtype = asl_get_type(obj);
                if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
-               else asl = _asl_open_default();
        }
 
        }
 
-       level = eval & LEVEL_MASK;
+       level = eval & EVAL_LEVEL_MASK;
        if (level > 7) level = 7;
        if (level > 7) level = 7;
-       eval &= EVAL_MASK;
        lmask = ASL_FILTER_MASK(level);
 
        if ((objtype == ASL_TYPE_CLIENT) && (asl->aslfile != NULL)) use_global_lock = 1;
        lmask = ASL_FILTER_MASK(level);
 
        if ((objtype == ASL_TYPE_CLIENT) && (asl->aslfile != NULL)) use_global_lock = 1;
@@ -1001,22 +1111,7 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m
        if (sendmsg == NULL) return ASL_STATUS_FAILED;
 
        /* Set "ASLOption store" if tunneling */
        if (sendmsg == NULL) return ASL_STATUS_FAILED;
 
        /* Set "ASLOption store" if tunneling */
-       if (eval & EVAL_TUNNEL)
-       {
-               const char *val = NULL;
-               status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL);
-               if ((status != 0) || (val == NULL))
-               {
-                       asl_msg_set_key_val(sendmsg, ASL_KEY_OPTION, ASL_OPT_STORE);
-               }
-               else
-               {
-                       char *option = NULL;
-                       asprintf(&option, "%s %s", ASL_OPT_STORE, val);
-                       asl_msg_set_key_val(sendmsg, ASL_KEY_OPTION, option);
-                       free(option);
-               }
-       }
+       if (eval & EVAL_TUNNEL) _asl_set_option(sendmsg, ASL_OPT_STORE);
 
        outstatus = -1;
 
 
        outstatus = -1;
 
@@ -1062,28 +1157,34 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m
         * - Environment variable ASL_QUOTA_DISABLED == 1
         * - /etc/asl/.noquota existed at the time that the process started
         *
         * - Environment variable ASL_QUOTA_DISABLED == 1
         * - /etc/asl/.noquota existed at the time that the process started
         *
-        * Note that we just check /etc/asl/.noquota once, since it would be
+        * We just check /etc/asl/.noquota once, since it would be
         * expensive to stat() for every log message.
         * expensive to stat() for every log message.
+        *
+        * We only check the Environment variable once, since getenv() is
+        * not thread safe.  If someone is changing the environment,
+        * this can crash.
         */
         */
-       
+
        dispatch_once(&noquota_once, ^{
                struct stat sb;
                memset(&sb, 0, sizeof(struct stat));
        dispatch_once(&noquota_once, ^{
                struct stat sb;
                memset(&sb, 0, sizeof(struct stat));
-               if (stat(NOQUOTA_FILE_PATH, &sb) == 0) _asl_global.quota = UINT32_MAX;
-       });
-       
-       if (_asl_global.quota != UINT32_MAX)
-       {
-               const char *qtest = getenv(NOQUOTA_ENV);
-               if ((qtest != NULL) && (!strcmp(qtest, "1")))
+
+               int save_errno = errno;
+
+               if (stat(NOQUOTA_FILE_PATH, &sb) == 0)
                {
                        _asl_global.quota = UINT32_MAX;
                {
                        _asl_global.quota = UINT32_MAX;
-
-                       qd_msg = asl_base_msg(asl, QUOTA_LEVEL, &tval, sstr, fstr, QUOTA_DISABLED_MSG);
-                       asl_msg_set_key_val(qd_msg, ASL_KEY_OPTION, ASL_OPT_STORE);
                }
                }
-       }
-       
+               else
+               {
+                       const char *qtest = getenv(NOQUOTA_ENV);
+                       if ((qtest != NULL) && (!strcmp(qtest, "1"))) _asl_global.quota = UINT32_MAX;
+               }
+
+               /* reset errno since we want stat() to fail silently */
+               errno = save_errno;
+       });
+
        if (((eval & EVAL_TUNNEL) == 0) && (_asl_global.quota != UINT32_MAX))
        {
                time_t last_send = _asl_global.last_send;
        if (((eval & EVAL_TUNNEL) == 0) && (_asl_global.quota != UINT32_MAX))
        {
                time_t last_send = _asl_global.last_send;
@@ -1115,7 +1216,7 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m
                        }
                        else
                        {
                        }
                        else
                        {
-                               eval &= ~EVAL_SEND;
+                               eval &= ~EVAL_SEND_ASL;
                        }
                }
                else
                        }
                }
                else
@@ -1124,7 +1225,7 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m
                }
        }
 
                }
        }
 
-       if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND))
+       if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND_ASL))
        {
                asl_string_t *send_str;
                const char *str;
        {
                asl_string_t *send_str;
                const char *str;
@@ -1146,9 +1247,31 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m
                        if ((str != NULL) && (vmsize != 0)) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
                        asl_msg_release(qd_msg);
                }
                        if ((str != NULL) && (vmsize != 0)) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
                        asl_msg_release(qd_msg);
                }
-       
+
                send_str = asl_msg_to_string_raw(ASL_STRING_MIG, sendmsg, "raw");
                len = asl_string_length(send_str);
                send_str = asl_msg_to_string_raw(ASL_STRING_MIG, sendmsg, "raw");
                len = asl_string_length(send_str);
+
+               if (len > LIBASL_MAX_MSG_SIZE)
+               {
+                       char tmp[256];
+
+                       snprintf(tmp, sizeof(tmp), SIZE_LIMIT_MSG, len, LIBASL_MAX_MSG_SIZE);
+                       asl_msg_t *limitmsg = asl_base_msg(asl, ASL_LEVEL_CRIT, &tval, sstr, fstr, tmp);
+
+                       asl_string_release(send_str);
+                       len = 0;
+
+                       if (limitmsg != NULL)
+                       {
+                               /* Set "ASLOption store" if tunneling */
+                               if (eval & EVAL_TUNNEL) _asl_set_option(limitmsg, ASL_OPT_STORE);
+
+                               send_str = asl_msg_to_string_raw(ASL_STRING_MIG, limitmsg, "raw");
+                               len = asl_string_length(send_str);
+                               asl_msg_release(limitmsg);
+                       }
+               }
+
                vmsize = asl_string_allocated_size(send_str);
                str = asl_string_release_return_bytes(send_str);
 
                vmsize = asl_string_allocated_size(send_str);
                str = asl_string_release_return_bytes(send_str);
 
@@ -1552,7 +1675,7 @@ _asl_server_control_query(void)
        res = NULL;
        reslen = 0;
 
        res = NULL;
        reslen = 0;
 
-       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
+       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
        if (kstatus != KERN_SUCCESS) return NULL;
 
        memmove(vmstr, ctlstr, len);
        if (kstatus != KERN_SUCCESS) return NULL;
 
        memmove(vmstr, ctlstr, len);
@@ -1655,7 +1778,7 @@ asl_open_path(const char *path, uint32_t opts)
                        if (opts & ASL_OPT_CREATE_STORE)
                        {
                                if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
                        if (opts & ASL_OPT_CREATE_STORE)
                        {
                                if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
-                               return (asl_object_t)fout;
+                               return (asl_object_t)sout;
                        }
                        else
                        {
                        }
                        else
                        {
index 4dd77db345c98e670b1f18962fe1ffa999d13776..7026a507d3a0d0c7741e2f15a4504a273878127f 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -136,6 +136,10 @@ asl_client_open(const char *ident, const char *facility, uint32_t opts)
 
        client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE);
 
 
        client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE);
 
+       client->filter |= EVAL_ACTIVE;
+       if (!(opts & ASL_OPT_SHIM_NO_ASL)) client->filter |= EVAL_SEND_ASL;
+       if (!(opts & ASL_OPT_SHIM_NO_TRACE)) client->filter |= EVAL_SEND_TRACE;
+       
        if (client->options & ASL_OPT_STDERR)
        {
                /* only add stderr if it is valid */
        if (client->options & ASL_OPT_STDERR)
        {
                /* only add stderr if it is valid */
@@ -161,6 +165,7 @@ asl_client_open_from_file(int descriptor, const char *ident, const char *facilit
        if (client == NULL) return NULL;
 
        client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG);
        if (client == NULL) return NULL;
 
        client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG);
+       client->filter |= (EVAL_ACTIVE | EVAL_SEND_ASL);
 
        status = asl_file_open_write_fd(descriptor, &(client->aslfile));
        if (status != ASL_STATUS_OK)
 
        status = asl_file_open_write_fd(descriptor, &(client->aslfile));
        if (status != ASL_STATUS_OK)
@@ -224,7 +229,7 @@ _do_server_match(asl_msg_list_t *qlist, size_t *last, size_t start, size_t count
 
        if (str == NULL) return NULL;
 
 
        if (str == NULL) return NULL;
 
-       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
+       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
        if (kstatus != KERN_SUCCESS) return NULL;
 
        memmove(vmstr, str, len);
        if (kstatus != KERN_SUCCESS) return NULL;
 
        memmove(vmstr, str, len);
@@ -274,7 +279,7 @@ _do_server_search(asl_msg_t *q)
 
        if (str == NULL) return NULL;
 
 
        if (str == NULL) return NULL;
 
-       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
+       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
        if (kstatus != KERN_SUCCESS) return NULL;
 
        memmove(vmstr, str, len);
        if (kstatus != KERN_SUCCESS) return NULL;
 
        memmove(vmstr, str, len);
@@ -367,18 +372,40 @@ asl_client_search(asl_client_t *client, asl_msg_t *query)
 #pragma mark -
 #pragma mark output control
 
 #pragma mark -
 #pragma mark output control
 
-/* returns last filter value, or -1 on error */
+/*
+ * Returns last filter value, or -1 on error.
+ * Note that this allows ASL_FILTER_MASK_TUNNEL (0x100) to be set.
+ * That is SPI that's used by some clients.
+ */
 int
 asl_client_set_filter(asl_client_t *client, int filter)
 {
 int
 asl_client_set_filter(asl_client_t *client, int filter)
 {
-       int last;
-
        if (client == NULL) return -1;
        if (client == NULL) return -1;
-       last = client->filter;
+
+       uint32_t allbits = client->filter;
+       int last = allbits & (~EVAL_ACTION_MASK);
+       client->filter = (allbits & EVAL_ACTION_MASK) | (filter & (~EVAL_ACTION_MASK));
+       return last;
+}
+
+/* SPI */
+uint32_t
+asl_client_set_control(asl_client_t *client, uint32_t filter)
+{
+       if (client == NULL) return UINT32_MAX;
+
+       uint32_t last = client->filter;
        client->filter = filter;
        return last;
 }
 
        client->filter = filter;
        return last;
 }
 
+uint32_t
+asl_client_get_control(asl_client_t *client)
+{
+       if (client == NULL) return UINT32_MAX;
+       return client->filter;
+}
+
 ASL_STATUS
 asl_client_add_output_file(asl_client_t *client, int descriptor, const char *mfmt, const char *tfmt, int filter, int text_encoding)
 {
 ASL_STATUS
 asl_client_add_output_file(asl_client_t *client, int descriptor, const char *mfmt, const char *tfmt, int filter, int text_encoding)
 {
@@ -414,7 +441,9 @@ asl_client_add_output_file(asl_client_t *client, int descriptor, const char *mfm
        client->out_list[client->out_count].fd = descriptor;
        client->out_list[client->out_count].encoding = text_encoding;
        client->out_list[client->out_count].filter = filter;
        client->out_list[client->out_count].fd = descriptor;
        client->out_list[client->out_count].encoding = text_encoding;
        client->out_list[client->out_count].filter = filter;
+       client->out_list[client->out_count].mfmt = NULL;
        if (mfmt != NULL) client->out_list[client->out_count].mfmt = strdup(mfmt);
        if (mfmt != NULL) client->out_list[client->out_count].mfmt = strdup(mfmt);
+       client->out_list[client->out_count].tfmt = NULL;
        if (tfmt != NULL) client->out_list[client->out_count].tfmt = strdup(tfmt);
 
        client->out_count++;
        if (tfmt != NULL) client->out_list[client->out_count].tfmt = strdup(tfmt);
 
        client->out_count++;
index 3ae25de912aa3fb8c9780c1509d597550eddf5a7..30de51b989b2446f9149e321cdbafb9ec8bc4306 100644 (file)
@@ -53,9 +53,6 @@ const char *ASL_LEVEL_TO_STRING[] =
        ASL_STRING_DEBUG
 };
 
        ASL_STRING_DEBUG
 };
 
-static char *asl_filesystem_path_database = NULL;
-static char *asl_filesystem_path_archive = NULL;
-
 /*
  * Message ID generation
  */
 /*
  * Message ID generation
  */
@@ -86,7 +83,7 @@ asl_core_get_service_port(int reset)
        static mach_port_t server_port = MACH_PORT_NULL;
        mach_port_t tmp;
        kern_return_t kstatus;
        static mach_port_t server_port = MACH_PORT_NULL;
        mach_port_t tmp;
        kern_return_t kstatus;
-       
+
        if ((reset != 0) && (server_port != MACH_PORT_NULL))
        {
                mach_port_t tmp = server_port;
        if ((reset != 0) && (server_port != MACH_PORT_NULL))
        {
                mach_port_t tmp = server_port;
@@ -327,12 +324,14 @@ const char *
 asl_filesystem_path(uint32_t place)
 {
        static dispatch_once_t once;
 asl_filesystem_path(uint32_t place)
 {
        static dispatch_once_t once;
+       static char *asl_filesystem_path_database = NULL;
+       static char *asl_filesystem_path_archive = NULL;
 
        dispatch_once(&once, ^{
                char *asl_var_log = NULL;
                const char *const_asl_var_log = "/var/log";
 
 
        dispatch_once(&once, ^{
                char *asl_var_log = NULL;
                const char *const_asl_var_log = "/var/log";
 
-#if TARGET_IPHONE_SIMULATOR
+#if TARGET_OS_SIMULATOR
                asl_var_log = getenv("SIMULATOR_LOG_ROOT");
 #endif
 
                asl_var_log = getenv("SIMULATOR_LOG_ROOT");
 #endif
 
@@ -346,12 +345,10 @@ asl_filesystem_path(uint32_t place)
        {
                case ASL_PLACE_DATABASE:
                {
        {
                case ASL_PLACE_DATABASE:
                {
-                       if (asl_filesystem_path_database == NULL) return ASL_PLACE_DATABASE_DEFAULT;
                        return asl_filesystem_path_database;
                }
                case ASL_PLACE_ARCHIVE:
                {
                        return asl_filesystem_path_database;
                }
                case ASL_PLACE_ARCHIVE:
                {
-                       if (asl_filesystem_path_archive == NULL) return ASL_PLACE_ARCHIVE_DEFAULT;
                        return asl_filesystem_path_archive;
                }
                default:
                        return asl_filesystem_path_archive;
                }
                default:
@@ -583,25 +580,25 @@ asl_core_str_match(const char *target, const char *mset, uint32_t mincount, uint
 {
        const char *x;
        uint32_t n;
 {
        const char *x;
        uint32_t n;
-       
+
        if (length == NULL) length = &n;
        if (length == NULL) length = &n;
-       
+
        if (target == NULL) return (mincount == 0);
        if (target == NULL) return (mincount == 0);
-       
+
        for (x = target, *length = 0; *x != '\0'; x++, *length = *length + 1)
        {
                char *s;
        for (x = target, *length = 0; *x != '\0'; x++, *length = *length + 1)
        {
                char *s;
-               
+
                if ((*length == maxcount) && (maxcount > 0)) return true;
                if (mset == NULL) continue;
                if ((*length == maxcount) && (maxcount > 0)) return true;
                if (mset == NULL) continue;
-               
+
                s = strchr(mset, *x);
                if ((s == NULL) && (flags & MFLAG_EXCLUDE)) continue;
                if ((s != NULL) && (flags & MFLAG_INCLUDE)) continue;
                s = strchr(mset, *x);
                if ((s == NULL) && (flags & MFLAG_EXCLUDE)) continue;
                if ((s != NULL) && (flags & MFLAG_INCLUDE)) continue;
-               
+
                break;
        }
                break;
        }
-       
+
        return (*length >= mincount);
 }
 
        return (*length >= mincount);
 }
 
@@ -609,15 +606,15 @@ bool
 asl_core_str_match_char(const char *target, const char c, uint32_t mincount, uint32_t flags, uint32_t *length)
 {
        uint32_t n;
 asl_core_str_match_char(const char *target, const char c, uint32_t mincount, uint32_t flags, uint32_t *length)
 {
        uint32_t n;
-       
+
        if (length == NULL) length = &n;
        *length = 0;
        if (length == NULL) length = &n;
        *length = 0;
-       
+
        if (target == NULL) return (mincount == 0);
        if (target == NULL) return (mincount == 0);
-       
+
        if ((*target == c) && (flags & MFLAG_INCLUDE)) *length = 1;
        if ((*target != c) && (flags & MFLAG_EXCLUDE)) *length = 1;
        if ((*target == c) && (flags & MFLAG_INCLUDE)) *length = 1;
        if ((*target != c) && (flags & MFLAG_EXCLUDE)) *length = 1;
-       
+
        return (*length >= mincount);
 }
 
        return (*length >= mincount);
 }
 
@@ -625,16 +622,96 @@ uint32_t
 asl_core_str_to_uint32(const char *target, uint32_t length)
 {
        uint32_t i, d, out = 0;
 asl_core_str_to_uint32(const char *target, uint32_t length)
 {
        uint32_t i, d, out = 0;
-       
+
        for (i = 0; i < length; i++)
        {
                d = target[i] - '0';
                out = (out * 10) + d;
        }
        for (i = 0; i < length; i++)
        {
                d = target[i] - '0';
                out = (out * 10) + d;
        }
-       
+
+       return out;
+}
+
+size_t
+asl_core_str_to_size(char *s)
+{
+       size_t len, n, max;
+       char x;
+
+       if (s == NULL) return 0;
+
+       len = strlen(s);
+       if (len == 0) return 0;
+
+       n = 1;
+       x = s[len - 1];
+       if (x > 90) x -= 32;
+       if (x == 'K') n = 1ll << 10;
+       else if (x == 'M') n = 1ll << 20;
+       else if (x == 'G') n = 1ll << 30;
+
+       max = atoll(s) * n;
+       return max;
+}
+
+time_t
+asl_core_str_to_time(char *s, uint32_t def_n)
+{
+       size_t len;
+       time_t n, out;
+       char x;
+
+       if (s == NULL) return 0;
+
+       len = strlen(s);
+       if (len == 0) return 0;
+
+       n = def_n;
+
+       x = s[len - 1];
+       if (x > 90) x -= 32;
+
+       if (x == 'S') n = 1;
+       else if (x == 'M') n = SECONDS_PER_MINUTE;
+       else if (x == 'H') n = SECONDS_PER_HOUR;
+       else if (x == 'D') n = SECONDS_PER_DAY;
+
+       out = atoll(s) * n;
        return out;
 }
 
        return out;
 }
 
+void
+asl_core_time_to_str(time_t s, char *str, size_t len)
+{
+       char days[32], hms[32];
+       uint32_t d, h, m;
+
+       d = s / SECONDS_PER_DAY;
+       s %= SECONDS_PER_DAY;
+
+       h = s / SECONDS_PER_HOUR;
+       s %= SECONDS_PER_HOUR;
+
+       m = s / SECONDS_PER_MINUTE;
+       s %= SECONDS_PER_MINUTE;
+
+       memset(days, 0, sizeof(days));
+       if (d > 0) snprintf(days, sizeof(days), "%u day%s", d, (d == 1) ? "" : "s");
+
+       memset(hms, 0, sizeof(hms));
+       snprintf(hms, sizeof(hms), "%02u:%02u:%02lld", h, m, (long long) s);
+
+       if ((h + m + s) == 0)
+       {
+               if (d == 0) snprintf(str, len, "0");
+               else snprintf(str, len, "%s", days);
+               return;
+       }
+
+       if (d == 0) snprintf(str, len, "%s", hms);
+       else snprintf(str, len, "%s %s", days, hms);
+}
+
 static bool
 asl_core_str_match_absolute_or_relative_time(const char *target, time_t *tval, uint32_t *tlen)
 {
 static bool
 asl_core_str_match_absolute_or_relative_time(const char *target, time_t *tval, uint32_t *tlen)
 {
@@ -643,37 +720,37 @@ asl_core_str_match_absolute_or_relative_time(const char *target, time_t *tval, u
        bool test;
        const char *p;
        time_t start = 0;
        bool test;
        const char *p;
        time_t start = 0;
-       
+
        if (target == NULL) return false;
        if (target == NULL) return false;
-       
+
        /* [+-] */
        p = target;
        test = asl_core_str_match(p, "+-", 0, 1, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* [+-] */
        p = target;
        test = asl_core_str_match(p, "+-", 0, 1, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        if (len == 1)
        {
                /* relative time */
                start = time(NULL);
                if (*p == '-') sign = -1;
        }
        if (len == 1)
        {
                /* relative time */
                start = time(NULL);
                if (*p == '-') sign = -1;
        }
-       
+
        /* [0-9]+ */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
        val = asl_core_str_to_uint32(p, len);
        /* [0-9]+ */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
        val = asl_core_str_to_uint32(p, len);
-       
+
        /* [shmdw] */
        p += len;
        test = asl_core_str_match(p, "SsMmHhDdWw", 0, 1, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* [shmdw] */
        p += len;
        test = asl_core_str_match(p, "SsMmHhDdWw", 0, 1, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        if ((*p == 'M') || (*p == 'm')) val *= SECONDS_PER_MINUTE;
        else if ((*p == 'H') || (*p == 'h')) val *= SECONDS_PER_HOUR;
        else if ((*p == 'D') || (*p == 'd')) val *= SECONDS_PER_DAY;
        else if ((*p == 'W') || (*p == 'w')) val *= SECONDS_PER_WEEK;
        if ((*p == 'M') || (*p == 'm')) val *= SECONDS_PER_MINUTE;
        else if ((*p == 'H') || (*p == 'h')) val *= SECONDS_PER_HOUR;
        else if ((*p == 'D') || (*p == 'd')) val *= SECONDS_PER_DAY;
        else if ((*p == 'W') || (*p == 'w')) val *= SECONDS_PER_WEEK;
-       
+
        /* matched string must be followed by space, tab, newline (not counted in length) */
        p += len;
        if (*p != '\0')
        /* matched string must be followed by space, tab, newline (not counted in length) */
        p += len;
        if (*p != '\0')
@@ -681,10 +758,10 @@ asl_core_str_match_absolute_or_relative_time(const char *target, time_t *tval, u
                test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
                if (!test) return false;
        }
                test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
                if (!test) return false;
        }
-       
+
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = start + (sign * val);
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = start + (sign * val);
-       
+
        return true;
 }
 
        return true;
 }
 
@@ -704,7 +781,7 @@ _month_num(const char *s)
        if (!strncasecmp(s, "nov", 3)) return 10;
        if (!strncasecmp(s, "dec", 3)) return 11;
        return -1;
        if (!strncasecmp(s, "nov", 3)) return 10;
        if (!strncasecmp(s, "dec", 3)) return 11;
        return -1;
-       
+
 }
 
 /*
 }
 
 /*
@@ -718,71 +795,71 @@ asl_core_str_match_c_time(const char *target, time_t *tval, uint32_t *tlen)
        const char *p;
        struct tm t;
        time_t now;
        const char *p;
        struct tm t;
        time_t now;
-       
+
        if (target == NULL) return false;
        memset(&t, 0, sizeof(t));
        if (target == NULL) return false;
        memset(&t, 0, sizeof(t));
-       
+
        /* determine current date */
        now = time(NULL);
        localtime_r(&now, &t);
        y = t.tm_year;
        memset(&t, 0, sizeof(t));
        t.tm_year = y;
        /* determine current date */
        now = time(NULL);
        localtime_r(&now, &t);
        y = t.tm_year;
        memset(&t, 0, sizeof(t));
        t.tm_year = y;
-       
+
        /* Mth */
        p = target;
        t.tm_mon = _month_num(p);
        len = 3;
        if (t.tm_mon == -1) return false;
        /* Mth */
        p = target;
        t.tm_mon = _month_num(p);
        len = 3;
        if (t.tm_mon == -1) return false;
-       
+
        /* whitespace */
        p += len;
        test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* whitespace */
        p += len;
        test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        /* [D]D */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_mday = asl_core_str_to_uint32(p, len);
        if (t.tm_mday > 31) return false;
        /* [D]D */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_mday = asl_core_str_to_uint32(p, len);
        if (t.tm_mday > 31) return false;
-       
+
        /* whitespace */
        p += len;
        test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* whitespace */
        p += len;
        test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        /* [h]h */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_hour = asl_core_str_to_uint32(p, len);
        if (t.tm_hour > 23) return false;
        /* [h]h */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_hour = asl_core_str_to_uint32(p, len);
        if (t.tm_hour > 23) return false;
-       
+
        /* : */
        p += len;
        if (*p != ':') return false;
        len = 1;
        /* : */
        p += len;
        if (*p != ':') return false;
        len = 1;
-       
+
        /* mm */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_min = asl_core_str_to_uint32(p, len);
        if (t.tm_min > 59) return false;
        /* mm */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_min = asl_core_str_to_uint32(p, len);
        if (t.tm_min > 59) return false;
-       
+
        /* : */
        p += len;
        if (*p != ':') return false;
        len = 1;
        /* : */
        p += len;
        if (*p != ':') return false;
        len = 1;
-       
+
        /* ss */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_sec = asl_core_str_to_uint32(p, len);
        if (t.tm_sec > 59) return false;
        /* ss */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_sec = asl_core_str_to_uint32(p, len);
        if (t.tm_sec > 59) return false;
-       
+
        /* matched string must be followed by space, tab, newline (not counted in length) */
        p += len;
        if (*p != '\0')
        /* matched string must be followed by space, tab, newline (not counted in length) */
        p += len;
        if (*p != '\0')
@@ -790,12 +867,12 @@ asl_core_str_match_c_time(const char *target, time_t *tval, uint32_t *tlen)
                test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
                if (!test) return false;
        }
                test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
                if (!test) return false;
        }
-       
+
        t.tm_isdst = -1;
        t.tm_isdst = -1;
-       
+
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = mktime(&t);
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = mktime(&t);
-       
+
        return true;
 }
 
        return true;
 }
 
@@ -809,21 +886,21 @@ asl_core_str_match_dotted_time(const char *target, time_t *tval, uint32_t *tlen)
        bool test;
        const char *p;
        struct tm t;
        bool test;
        const char *p;
        struct tm t;
-       
+
        if (target == NULL) return false;
        memset(&t, 0, sizeof(t));
        if (target == NULL) return false;
        memset(&t, 0, sizeof(t));
-       
+
        /* YYYY */
        p = target;
        test = asl_core_str_match(p, DIGITS, 4, 4, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_year = asl_core_str_to_uint32(p, len) - 1900;
        /* YYYY */
        p = target;
        test = asl_core_str_match(p, DIGITS, 4, 4, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_year = asl_core_str_to_uint32(p, len) - 1900;
-       
+
        /* . */
        p += len;
        if (*p != '.') return false;
        len = 1;
        /* . */
        p += len;
        if (*p != '.') return false;
        len = 1;
-       
+
        /* [M]M */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
        /* [M]M */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
@@ -832,65 +909,65 @@ asl_core_str_match_dotted_time(const char *target, time_t *tval, uint32_t *tlen)
        if (t.tm_mon < 1) return false;
        if (t.tm_mon > 12) return false;
        t.tm_mon -= 1;
        if (t.tm_mon < 1) return false;
        if (t.tm_mon > 12) return false;
        t.tm_mon -= 1;
-       
+
        /* . */
        p += len;
        if (*p != '.') return false;
        len = 1;
        /* . */
        p += len;
        if (*p != '.') return false;
        len = 1;
-       
+
        /* [D]D */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_mday = asl_core_str_to_uint32(p, len);
        if (t.tm_mday > 31) return false;
        /* [D]D */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_mday = asl_core_str_to_uint32(p, len);
        if (t.tm_mday > 31) return false;
-       
+
        /* whitespace */
        p += len;
        test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* whitespace */
        p += len;
        test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        /* [h]h */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_hour = asl_core_str_to_uint32(p, len);
        if (t.tm_hour > 23) return false;
        /* [h]h */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_hour = asl_core_str_to_uint32(p, len);
        if (t.tm_hour > 23) return false;
-       
+
        /* : */
        p += len;
        if (*p != ':') return false;
        len = 1;
        /* : */
        p += len;
        if (*p != ':') return false;
        len = 1;
-       
+
        /* mm */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_min = asl_core_str_to_uint32(p, len);
        if (t.tm_min > 59) return false;
        /* mm */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_min = asl_core_str_to_uint32(p, len);
        if (t.tm_min > 59) return false;
-       
+
        /* : */
        p += len;
        if (*p != ':') return false;
        len = 1;
        /* : */
        p += len;
        if (*p != ':') return false;
        len = 1;
-       
+
        /* ss */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_sec = asl_core_str_to_uint32(p, len);
        if (t.tm_sec > 59) return false;
        /* ss */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_sec = asl_core_str_to_uint32(p, len);
        if (t.tm_sec > 59) return false;
-       
+
        /* whitespace */
        p += len;
        test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* whitespace */
        p += len;
        test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        /* UTC */
        p += len;
        if (strncmp(p, "UTC", 3)) return false;
        len = 3;
        /* UTC */
        p += len;
        if (strncmp(p, "UTC", 3)) return false;
        len = 3;
-       
+
        /* matched string must be followed by space, tab, newline (not counted in length) */
        p += len;
        if (*p != '\0')
        /* matched string must be followed by space, tab, newline (not counted in length) */
        p += len;
        if (*p != '\0')
@@ -898,10 +975,10 @@ asl_core_str_match_dotted_time(const char *target, time_t *tval, uint32_t *tlen)
                test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
                if (!test) return false;
        }
                test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
                if (!test) return false;
        }
-       
+
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = timegm(&t);
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = timegm(&t);
-       
+
        return true;
 }
 
        return true;
 }
 
@@ -916,21 +993,21 @@ asl_core_str_match_iso_8601_time(const char *target, time_t *tval, uint32_t *tle
        const char *p;
        struct tm t;
        int32_t tzh, tzs, sign = -1;
        const char *p;
        struct tm t;
        int32_t tzh, tzs, sign = -1;
-       
+
        if (target == NULL) return false;
        memset(&t, 0, sizeof(t));
        if (target == NULL) return false;
        memset(&t, 0, sizeof(t));
-       
+
        /* YYYY */
        p = target;
        test = asl_core_str_match(p, DIGITS, 4, 4, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_year = asl_core_str_to_uint32(p, len) - 1900;
        /* YYYY */
        p = target;
        test = asl_core_str_match(p, DIGITS, 4, 4, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_year = asl_core_str_to_uint32(p, len) - 1900;
-       
+
        /* [-] */
        p += len;
        test = asl_core_str_match_char(p, '-', 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* [-] */
        p += len;
        test = asl_core_str_match_char(p, '-', 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        /* MM */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        /* MM */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
@@ -939,72 +1016,72 @@ asl_core_str_match_iso_8601_time(const char *target, time_t *tval, uint32_t *tle
        if (t.tm_mon < 1) return false;
        if (t.tm_mon > 12) return false;
        t.tm_mon -= 1;
        if (t.tm_mon < 1) return false;
        if (t.tm_mon > 12) return false;
        t.tm_mon -= 1;
-       
+
        /* [-] */
        p += len;
        test = asl_core_str_match_char(p, '-', 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* [-] */
        p += len;
        test = asl_core_str_match_char(p, '-', 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        /* DD */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_mday = asl_core_str_to_uint32(p, len);
        if (t.tm_mday > 31) return false;
        /* DD */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_mday = asl_core_str_to_uint32(p, len);
        if (t.tm_mday > 31) return false;
-       
+
        /* T or t */
        p += len;
        test = asl_core_str_match(p, "Tt", 1, 1, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* T or t */
        p += len;
        test = asl_core_str_match(p, "Tt", 1, 1, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        /* hh */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_hour = asl_core_str_to_uint32(p, len);
        if (t.tm_hour > 23) return false;
        /* hh */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_hour = asl_core_str_to_uint32(p, len);
        if (t.tm_hour > 23) return false;
-       
+
        /* [:] */
        p += len;
        test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* [:] */
        p += len;
        test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        /* mm */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_min = asl_core_str_to_uint32(p, len);
        if (t.tm_min > 59) return false;
        /* mm */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_min = asl_core_str_to_uint32(p, len);
        if (t.tm_min > 59) return false;
-       
+
        /* [:] */
        p += len;
        test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* [:] */
        p += len;
        test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        /* ss */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_sec = asl_core_str_to_uint32(p, len);
        if (t.tm_sec > 59) return false;
        /* ss */
        p += len;
        test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        t.tm_sec = asl_core_str_to_uint32(p, len);
        if (t.tm_sec > 59) return false;
-       
+
        p += len;
        p += len;
-       
+
        /* default to local time if we hit the end of the string */
        if ((*p == '\0') || (*p == ' ') || (*p == '\t') || (*p == '\n'))
        {
                t.tm_isdst = -1;
        /* default to local time if we hit the end of the string */
        if ((*p == '\0') || (*p == ' ') || (*p == '\t') || (*p == '\n'))
        {
                t.tm_isdst = -1;
-               
+
                if (tlen != NULL) *tlen = p - target;
                if (tval != NULL) *tval = mktime(&t);
                if (tlen != NULL) *tlen = p - target;
                if (tval != NULL) *tval = mktime(&t);
-               
+
                return true;
        }
                return true;
        }
-       
+
        /* Z, z, +, or - */
        test = asl_core_str_match(p, "Zz+-", 1, 1, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* Z, z, +, or - */
        test = asl_core_str_match(p, "Zz+-", 1, 1, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        if ((*p == 'Z') || (*p == 'z'))
        {
                /* matched string must be followed by space, tab, newline (not counted in length) */
        if ((*p == 'Z') || (*p == 'z'))
        {
                /* matched string must be followed by space, tab, newline (not counted in length) */
@@ -1014,36 +1091,36 @@ asl_core_str_match_iso_8601_time(const char *target, time_t *tval, uint32_t *tle
                        test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
                        if (!test) return false;
                }
                        test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
                        if (!test) return false;
                }
-               
+
                if (tlen != NULL) *tlen = p - target;
                if (tval != NULL) *tval = timegm(&t);
                if (tlen != NULL) *tlen = p - target;
                if (tval != NULL) *tval = timegm(&t);
-               
+
                return true;
        }
                return true;
        }
-       
+
        if (*p == '-') sign = 1;
        if (*p == '-') sign = 1;
-       
+
        /* [h]h */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        tzh = asl_core_str_to_uint32(p, len);
        if (tzh > 23) return false;
        /* [h]h */
        p += len;
        test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        tzh = asl_core_str_to_uint32(p, len);
        if (tzh > 23) return false;
-       
+
        /* [:] */
        p += len;
        test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
        /* [:] */
        p += len;
        test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len);
        if (!test) return false;
-       
+
        /* mm */
        p += len;
        test = asl_core_str_match(p, DIGITS, 0, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        tzs = asl_core_str_to_uint32(p, len);
        if (tzs > 59) return false;
        /* mm */
        p += len;
        test = asl_core_str_match(p, DIGITS, 0, 2, MFLAG_INCLUDE, &len);
        if (!test) return false;
        tzs = asl_core_str_to_uint32(p, len);
        if (tzs > 59) return false;
-       
+
        t.tm_sec += (sign * (tzh * SECONDS_PER_HOUR) + (tzs * SECONDS_PER_MINUTE));
        t.tm_sec += (sign * (tzh * SECONDS_PER_HOUR) + (tzs * SECONDS_PER_MINUTE));
-       
+
        /* matched string must be followed by space, tab, newline (not counted in length) */
        p += len;
        if (*p != '\0')
        /* matched string must be followed by space, tab, newline (not counted in length) */
        p += len;
        if (*p != '\0')
@@ -1051,10 +1128,10 @@ asl_core_str_match_iso_8601_time(const char *target, time_t *tval, uint32_t *tle
                test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
                if (!test) return false;
        }
                test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
                if (!test) return false;
        }
-       
+
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = timegm(&t);
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = timegm(&t);
-       
+
        return true;
 }
 
        return true;
 }
 
@@ -1063,55 +1140,55 @@ asl_core_parse_time(const char *in, uint32_t *tlen)
 {
        time_t tval = 0;
        uint32_t inlen;
 {
        time_t tval = 0;
        uint32_t inlen;
-       
+
        if (tlen != NULL) *tlen = 0;
 
        if (in == NULL) return -1;
        if (tlen != NULL) *tlen = 0;
 
        if (in == NULL) return -1;
-       
+
        /*
         * Heuristics to determine the string format.
         * Warning: this code must be checked and may need to be adjusted if new formats are added.
         */
        inlen = strlen(in);
        if (inlen == 0) return -1;
        /*
         * Heuristics to determine the string format.
         * Warning: this code must be checked and may need to be adjusted if new formats are added.
         */
        inlen = strlen(in);
        if (inlen == 0) return -1;
-       
+
        /* leading plus or minus means it must be a relative time */
        if ((in[0] == '+') || (in[0] == '-'))
        {
                if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval;
                return -1;
        }
        /* leading plus or minus means it must be a relative time */
        if ((in[0] == '+') || (in[0] == '-'))
        {
                if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval;
                return -1;
        }
-       
+
        /* leading alphabetic char means it must be ctime() format */
        if (((in[0] >= 'a') && (in[0] <= 'z')) || ((in[0] >= 'A') && (in[0] <= 'Z')))
        {
                if (asl_core_str_match_c_time(in, &tval, tlen)) return tval;
                return -1;
        }
        /* leading alphabetic char means it must be ctime() format */
        if (((in[0] >= 'a') && (in[0] <= 'z')) || ((in[0] >= 'A') && (in[0] <= 'Z')))
        {
                if (asl_core_str_match_c_time(in, &tval, tlen)) return tval;
                return -1;
        }
-       
+
        /* only absolute, dotted, or iso8601 formats at this point */
        /* only absolute, dotted, or iso8601 formats at this point */
-       
+
        /* one to for chars means it must be absolute */
        if (inlen < 5)
        {
                if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval;
                return -1;
        }
        /* one to for chars means it must be absolute */
        if (inlen < 5)
        {
                if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval;
                return -1;
        }
-       
+
        /* check for dot */
        if (in[4] == '.')
        {
                if (asl_core_str_match_dotted_time(in, &tval, tlen)) return tval;
                return -1;
        }
        /* check for dot */
        if (in[4] == '.')
        {
                if (asl_core_str_match_dotted_time(in, &tval, tlen)) return tval;
                return -1;
        }
-       
+
        /* only absolute or iso8601 at this point */
        /* only absolute or iso8601 at this point */
-       
+
        /* check for absolute first, since that's quicker */
        if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval;
        /* check for absolute first, since that's quicker */
        if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval;
-       
+
        if (asl_core_str_match_iso_8601_time(in, &tval, tlen)) return tval;
        if (asl_core_str_match_iso_8601_time(in, &tval, tlen)) return tval;
-       
+
        return -1;
 }
 
        return -1;
 }
 
index ceef2c99d2a46bcf67bc478fea4796536d6d308d..4b635291028bc2bcb6c434c5b3cb522278ece6a0 100644 (file)
@@ -181,6 +181,34 @@ asl_file_read_uint64(asl_file_t *s, off_t off, uint64_t *out)
        return ASL_STATUS_OK;
 }
 
        return ASL_STATUS_OK;
 }
 
+static file_string_t *
+file_string_create(asl_file_t *s)
+{
+       if ((s != NULL) && (s->string_spare != NULL))
+       {
+               file_string_t *out = s->string_spare;
+               s->string_spare = NULL;
+               return out;
+       }
+
+       return (file_string_t *)calloc(1, sizeof(file_string_t));
+}
+
+static void
+file_string_dispose(asl_file_t *s, file_string_t *x)
+{
+       if ((s != NULL) && (s->string_spare == NULL))
+       {
+               s->string_spare = x;
+               memset(s->string_spare, 0, sizeof(file_string_t));
+       }
+       else
+       {
+               free(x);
+       }
+}
+
+
 asl_file_t *
 asl_file_retain(asl_file_t *s)
 {
 asl_file_t *
 asl_file_retain(asl_file_t *s)
 {
@@ -224,6 +252,8 @@ _asl_file_free_internal(asl_file_t *s)
                s->string_list = x;
        }
 
                s->string_list = x;
        }
 
+       free(s->string_spare);
+
        if (s->store != NULL) fclose(s->store);
        if (s->scratch != NULL) free(s->scratch);
 
        if (s->store != NULL) fclose(s->store);
        if (s->scratch != NULL) free(s->scratch);
 
@@ -465,6 +495,18 @@ asl_file_open_write(const char *path, mode_t mode, uid_t uid, gid_t gid, asl_fil
                                if ((out->last + last_len) > out->file_size) out->last = 0;
                        }
 
                                if ((out->last + last_len) > out->file_size) out->last = 0;
                        }
 
+                       if (out->last != 0)
+                       {
+                               /* skip type (uint16_t), len (uint32_t), and next (uint64_t) */
+                               off = out->last + sizeof(uint16_t) + sizeof (uint32_t) + sizeof(uint64_t);
+                               status = asl_file_read_uint64(out, off, &(out->last_mid));
+                               if (status != ASL_STATUS_OK)
+                               {
+                                       asl_file_close(out);
+                                       return status;
+                               }
+                       }
+
                        aslstatus = asl_file_read_set_position(out, ASL_FILE_POSITION_LAST);
                        if (aslstatus != ASL_STATUS_OK)
                        {
                        aslstatus = asl_file_read_set_position(out, ASL_FILE_POSITION_LAST);
                        if (aslstatus != ASL_STATUS_OK)
                        {
@@ -717,28 +759,34 @@ asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out)
                return ASL_STATUS_OK;
        }
 
                return ASL_STATUS_OK;
        }
 
-       /* check the cache */
-       hash = asl_core_string_hash(str, len);
+       /* cached strings include trailing nul */
+       len++;
 
 
-       sp = NULL;
-       for (sx = s->string_list; sx != NULL; sx = sx->next)
+       if (len <= CACHE_MAX_STRING_LEN)
        {
        {
-               if ((hash == sx->hash) && (!strcmp(str, sx->str)))
+               /* check the cache */
+               hash = asl_core_string_hash(str, len);
+
+               sp = NULL;
+               for (sx = s->string_list; sx != NULL; sx = sx->next)
                {
                {
-                       /* Move this string to the head of the list */
-                       if (sp != NULL)
+                       if ((hash == sx->hash) && (!strcmp(str, sx->str)))
                        {
                        {
-                               sl = s->string_list;
-                               sp->next = sx->next;
-                               sx->next = sl;
-                               s->string_list = sx;
+                               /* Move this string to the head of the list */
+                               if (sp != NULL)
+                               {
+                                       sl = s->string_list;
+                                       sp->next = sx->next;
+                                       sx->next = sl;
+                                       s->string_list = sx;
+                               }
+
+                               *out = sx->where;
+                               return ASL_STATUS_OK;
                        }
 
                        }
 
-                       *out = sx->where;
-                       return ASL_STATUS_OK;
+                       sp = sx;
                }
                }
-
-               sp = sx;
        }
 
        off = ftello(s->store);
        }
 
        off = ftello(s->store);
@@ -749,47 +797,56 @@ asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out)
        if (i != 1) return ASL_STATUS_WRITE_FAILED;
 
        /* Length (includes trailing nul) */
        if (i != 1) return ASL_STATUS_WRITE_FAILED;
 
        /* Length (includes trailing nul) */
-       x32 = htonl(len + 1);
+       x32 = htonl(len);
        i = fwrite(&x32, sizeof(uint32_t), 1, s->store);
        if (i != 1) return ASL_STATUS_WRITE_FAILED;
 
        /* String data (nul terminated) */
        i = fwrite(&x32, sizeof(uint32_t), 1, s->store);
        if (i != 1) return ASL_STATUS_WRITE_FAILED;
 
        /* String data (nul terminated) */
-       i = fwrite(str, len + 1, 1, s->store);
+       i = fwrite(str, len, 1, s->store);
        if (i != 1) return ASL_STATUS_WRITE_FAILED;
 
        /* flush data */
        fflush(s->store);
 
        if (i != 1) return ASL_STATUS_WRITE_FAILED;
 
        /* flush data */
        fflush(s->store);
 
-       /* create file_string_t and insert into the cache */
-       sx = (file_string_t *)calloc(1, offsetof(file_string_t, str) + len + 1);
-       if (sx == NULL) return ASL_STATUS_NO_MEMORY;
+       /*
+        * Create file_string_t and insert into the cache, but only if the
+        * string is small.  This prevents a huge string from eating memory.
+        * It's unlikely that large strings will be very re-usable.
+        */
+       if (len <= CACHE_MAX_STRING_LEN)
+       {
+               sx = file_string_create(s);
+               if (sx == NULL) return ASL_STATUS_NO_MEMORY;
 
 
-       sx->where = off;
-       sx->hash = hash;
-       sx->next = s->string_list;
-       memcpy(sx->str, str, len);
+               sx->where = off;
+               sx->hash = hash;
+               sx->next = s->string_list;
 
 
-       s->string_list = sx;
+               /* includes trailing nul */
+               memcpy(sx->str, str, len);
 
 
-       if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_cache_count == CACHE_SIZE))
-       {
-               /* drop last (lru) string from cache */
-               sp = s->string_list;
-               sx = sp->next;
+               s->string_list = sx;
 
 
-               /* NB CACHE_SIZE must be > 1 */
-               while (sx->next != NULL)
+               if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_cache_count == CACHE_SIZE))
                {
                {
-                       sp = sx;
-                       sx = sx->next;
-               }
+                       /* drop last (lru) string from cache */
+                       sp = s->string_list;
+                       sx = sp->next;
 
 
-               sp->next = NULL;
-               free(sx);
-       }
-       else
-       {
-               s->string_cache_count++;
+                       /* NB CACHE_SIZE must be > 1 */
+                       while (sx->next != NULL)
+                       {
+                               sp = sx;
+                               sx = sx->next;
+                       }
+
+                       sp->next = NULL;
+                       file_string_dispose(s, sx);
+               }
+               else
+               {
+                       s->string_cache_count++;
+               }
        }
 
        *out = off;
        }
 
        *out = off;
@@ -800,6 +857,8 @@ asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out)
  * Encode an asl_msg_t *as a record structure.
  * Creates and caches strings.
  */
  * Encode an asl_msg_t *as a record structure.
  * Creates and caches strings.
  */
+#define KVSTACK_SIZE 128
+
 ASL_STATUS
 asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
 {
 ASL_STATUS
 asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
 {
@@ -807,6 +866,8 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
        uint32_t i, len, x, status;
        file_record_t r;
        uint64_t k, v;
        uint32_t i, len, x, status;
        file_record_t r;
        uint64_t k, v;
+       uint64_t kvstack[KVSTACK_SIZE];
+       uint64_t *kvmalloc = NULL;
        uint64_t *kvlist;
        off_t off;
        asl_msg_t *msg;
        uint64_t *kvlist;
        off_t off;
        asl_msg_t *msg;
@@ -822,6 +883,9 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
 
        memset(&r, 0, sizeof(file_record_t));
 
 
        memset(&r, 0, sizeof(file_record_t));
 
+       r.mid = UINT64_MAX;
+       if ((mid != NULL ) && (*mid != 0)) r.mid = *mid;
+
        r.flags = 0;
        r.level = ASL_LEVEL_DEBUG;
        r.pid = -1;
        r.flags = 0;
        r.level = ASL_LEVEL_DEBUG;
        r.pid = -1;
@@ -832,7 +896,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
        r.time = 0;
        r.nano = 0;
        r.prev = s->prev;
        r.time = 0;
        r.nano = 0;
        r.prev = s->prev;
-       kvlist = NULL;
+       kvlist = kvstack;
 
        key = NULL;
        val = NULL;
 
        key = NULL;
        val = NULL;
@@ -858,7 +922,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
                                status = asl_file_string_encode(s, val, &(r.host));
                                if (status != ASL_STATUS_OK)
                                {
                                status = asl_file_string_encode(s, val, &(r.host));
                                if (status != ASL_STATUS_OK)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        return status;
                                }
                        }
                                        return status;
                                }
                        }
@@ -870,7 +934,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
                                status = asl_file_string_encode(s, val, &(r.sender));
                                if (status != ASL_STATUS_OK)
                                {
                                status = asl_file_string_encode(s, val, &(r.sender));
                                if (status != ASL_STATUS_OK)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        return status;
                                }
                        }
                                        return status;
                                }
                        }
@@ -902,7 +966,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
                                status = asl_file_string_encode(s, val, &(r.message));
                                if (status != ASL_STATUS_OK)
                                {
                                status = asl_file_string_encode(s, val, &(r.message));
                                if (status != ASL_STATUS_OK)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        return status;
                                }
                        }
                                        return status;
                                }
                        }
@@ -914,7 +978,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
                                status = asl_file_string_encode(s, val, &(r.facility));
                                if (status != ASL_STATUS_OK)
                                {
                                status = asl_file_string_encode(s, val, &(r.facility));
                                if (status != ASL_STATUS_OK)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        return status;
                                }
                        }
                                        return status;
                                }
                        }
@@ -926,7 +990,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
                                status = asl_file_string_encode(s, val, &(r.refproc));
                                if (status != ASL_STATUS_OK)
                                {
                                status = asl_file_string_encode(s, val, &(r.refproc));
                                if (status != ASL_STATUS_OK)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        return status;
                                }
                        }
                                        return status;
                                }
                        }
@@ -938,7 +1002,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
                                status = asl_file_string_encode(s, val, &(r.session));
                                if (status != ASL_STATUS_OK)
                                {
                                status = asl_file_string_encode(s, val, &(r.session));
                                if (status != ASL_STATUS_OK)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        return status;
                                }
                        }
                                        return status;
                                }
                        }
@@ -961,7 +1025,11 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
                }
                else if (!strcmp(key, ASL_KEY_MSG_ID))
                {
                }
                else if (!strcmp(key, ASL_KEY_MSG_ID))
                {
-                       if (s->flags & ASL_FILE_FLAG_PRESERVE_MSG_ID) *mid = atoll(val);
+                       if (s->flags & ASL_FILE_FLAG_PRESERVE_MSG_ID)
+                       {
+                               r.mid = atoll(val);
+                               if (mid != NULL) *mid = r.mid;
+                       }
                }
                else if (!strcmp(key, ASL_KEY_OPTION))
                {
                }
                else if (!strcmp(key, ASL_KEY_OPTION))
                {
@@ -972,7 +1040,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
                        status = asl_file_string_encode(s, key, &k);
                        if (status != ASL_STATUS_OK)
                        {
                        status = asl_file_string_encode(s, key, &k);
                        if (status != ASL_STATUS_OK)
                        {
-                               if (kvlist != NULL) free(kvlist);
+                               free(kvmalloc);
                                return status;
                        }
 
                                return status;
                        }
 
@@ -982,23 +1050,24 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
                                status = asl_file_string_encode(s, val, &v);
                                if (status != ASL_STATUS_OK)
                                {
                                status = asl_file_string_encode(s, val, &v);
                                if (status != ASL_STATUS_OK)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        return status;
                                }
                        }
 
                                        return status;
                                }
                        }
 
-                       if (r.kvcount == 0)
+                       if (r.kvcount >= KVSTACK_SIZE)
                        {
                        {
-                               kvlist = (uint64_t *)calloc(2, sizeof(uint64_t));
-                       }
-                       else
-                       {
-                               kvlist = (uint64_t *)reallocf(kvlist, (r.kvcount + 2) * sizeof(uint64_t));
-                       }
+                               /* out of space for the kvlist on the stack - fall back to malloc */
+                               kvmalloc = reallocf(kvmalloc, (r.kvcount + 2) * sizeof(uint64_t));
+                               if (kvmalloc == NULL) return ASL_STATUS_NO_MEMORY;
 
 
-                       if (kvlist == NULL)
-                       {
-                               return ASL_STATUS_NO_MEMORY;
+                               kvlist = kvmalloc;
+
+                               if (r.kvcount == KVSTACK_SIZE)
+                               {
+                                       /* copy kvstack to kvmalloc */
+                                       for (i = 0; i < KVSTACK_SIZE; i++) kvmalloc[i] = kvstack[i];
+                               }
                        }
 
                        kvlist[r.kvcount++] = k;
                        }
 
                        kvlist[r.kvcount++] = k;
@@ -1022,14 +1091,10 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
 
        if (buf == NULL) return ASL_STATUS_NO_MEMORY;
 
 
        if (buf == NULL) return ASL_STATUS_NO_MEMORY;
 
-       if (*mid != 0)
+       if (r.mid == UINT64_MAX)
        {
        {
-               r.mid = *mid;
-       }
-       else
-       {
-               r.mid = asl_core_new_msg_id(0);
-               *mid = r.mid;
+               s->last_mid = s->last_mid + 1;
+               r.mid = s->last_mid;
        }
 
        p = buf;
        }
 
        p = buf;
@@ -1110,8 +1175,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
        _asl_put_64(r.prev, p);
        p += sizeof(uint64_t);
 
        _asl_put_64(r.prev, p);
        p += sizeof(uint64_t);
 
-       free(kvlist);
-       kvlist = NULL;
+       free(kvmalloc);
 
        /* write record at end of file */
        status = fseeko(s->store, 0, SEEK_END);
 
        /* write record at end of file */
        status = fseeko(s->store, 0, SEEK_END);
@@ -1161,7 +1225,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
 }
 
 static ASL_STATUS
 }
 
 static ASL_STATUS
-asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outlen)
+asl_file_fetch_object(asl_file_t *s, uint16_t fetch_type, uint64_t where, char **out, uint32_t *outlen)
 {
        char ils[9];
        char *p;
 {
        char ils[9];
        char *p;
@@ -1180,12 +1244,14 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle
 
        *out = NULL;
        *outlen = 0;
 
        *out = NULL;
        *outlen = 0;
-       
+
        inls = 0;
        x64 = asl_core_htonq(where);
        memcpy(&inls, &x64, 1);
        if (inls & 0x80)
        {
        inls = 0;
        x64 = asl_core_htonq(where);
        memcpy(&inls, &x64, 1);
        if (inls & 0x80)
        {
+               if (fetch_type != ASL_FILE_TYPE_STR) return ASL_STATUS_INVALID_STORE;
+
                /* inline string */
                inls &= 0x0f;
                if (inls > 7) return ASL_STATUS_INVALID_STORE;
                /* inline string */
                inls &= 0x0f;
                if (inls > 7) return ASL_STATUS_INVALID_STORE;
@@ -1200,6 +1266,38 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle
                return ASL_STATUS_OK;
        }
 
                return ASL_STATUS_OK;
        }
 
+       if (fetch_type == ASL_FILE_TYPE_STR)
+       {
+               /* check the string cache */
+               file_string_t *sx, *sp;
+
+               sp = NULL;
+               for (sx = s->string_list; sx != NULL; sx = sx->next)
+               {
+                       if (sx->where == where)
+                       {
+                               *out = strdup(sx->str);
+                               if (*out == NULL) return ASL_STATUS_NO_MEMORY;
+
+                               /* N.B. hash field is used to hold length when reading */
+                               *outlen = sx->hash;
+
+                               /* Move this string to the head of the list */
+                               if (sp != NULL)
+                               {
+                                       file_string_t *sl = s->string_list;
+                                       sp->next = sx->next;
+                                       sx->next = sl;
+                                       s->string_list = sx;
+                               }
+
+                               return ASL_STATUS_OK;
+                       }
+
+                       sp = sx;
+               }
+       }
+
        off = where;
        if ((off + sizeof(uint16_t) + sizeof(uint32_t)) > s->file_size) return ASL_STATUS_READ_FAILED;
 
        off = where;
        if ((off + sizeof(uint16_t) + sizeof(uint32_t)) > s->file_size) return ASL_STATUS_READ_FAILED;
 
@@ -1209,8 +1307,11 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle
        /* Type */
        status = fread(&type, sizeof(uint16_t), 1, s->store);
        if (status != 1) return ASL_STATUS_READ_FAILED;
        /* Type */
        status = fread(&type, sizeof(uint16_t), 1, s->store);
        if (status != 1) return ASL_STATUS_READ_FAILED;
+       type = ntohs(type);
        off += sizeof(uint16_t);
 
        off += sizeof(uint16_t);
 
+       if (type != fetch_type) return ASL_STATUS_INVALID_STORE;
+
        /* Length */
        len = 0;
        status = fread(&len, sizeof(uint32_t), 1, s->store);
        /* Length */
        len = 0;
        status = fread(&len, sizeof(uint32_t), 1, s->store);
@@ -1232,6 +1333,44 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle
        }
 
        *outlen = len;
        }
 
        *outlen = len;
+
+       if ((fetch_type == ASL_FILE_TYPE_STR) && (len <= CACHE_MAX_STRING_LEN))
+       {
+               file_string_t *sx = file_string_create(s);
+               if (sx != NULL)
+               {
+                       sx->where = where;
+
+                       /* N.B. hash field is used to hold length when reading */
+                       sx->hash = len;
+                       sx->next = s->string_list;
+                       memcpy(sx->str, *out, len);
+
+                       s->string_list = sx;
+
+                       if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_cache_count == CACHE_SIZE))
+                       {
+                               /* drop last (lru) string from cache */
+                               file_string_t *sp = s->string_list;
+                               sx = sp->next;
+
+                               /* NB CACHE_SIZE must be > 1 */
+                               while (sx->next != NULL)
+                               {
+                                       sp = sx;
+                                       sx = sx->next;
+                               }
+
+                               sp->next = NULL;
+                               file_string_dispose(s, sx);
+                       }
+                       else
+                       {
+                               s->string_cache_count++;
+                       }
+               }
+       }
+
        return ASL_STATUS_OK;
 }
 
        return ASL_STATUS_OK;
 }
 
@@ -1304,7 +1443,7 @@ asl_file_fetch_helper_str(asl_file_t *s, char **p, asl_msg_t *m, const char *key
        val = NULL;
        len = 0;
        status = ASL_STATUS_OK;
        val = NULL;
        len = 0;
        status = ASL_STATUS_OK;
-       if (out != 0) status = asl_file_fetch_object(s, out, &val, &len);
+       if (out != 0) status = asl_file_fetch_object(s, ASL_FILE_TYPE_STR, out, &val, &len);
 
        if (err != NULL) *err = status;
        if ((status == ASL_STATUS_OK) && (val != NULL))
 
        if (err != NULL) *err = status;
        if ((status == ASL_STATUS_OK) && (val != NULL))
@@ -1333,7 +1472,7 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, asl_msg_t **msg)
 
        buf = NULL;
        buflen = 0;
 
        buf = NULL;
        buflen = 0;
-       status = asl_file_fetch_object(s, where, &buf, &buflen);
+       status = asl_file_fetch_object(s, ASL_FILE_TYPE_MSG, where, &buf, &buflen);
        if ((status != ASL_STATUS_OK) || (buf == NULL))
        {
                s->cursor = 0;
        if ((status != ASL_STATUS_OK) || (buf == NULL))
        {
                s->cursor = 0;
@@ -1403,7 +1542,7 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, asl_msg_t **msg)
                kv = _asl_get_64(p);
                p += sizeof(uint64_t);
 
                kv = _asl_get_64(p);
                p += sizeof(uint64_t);
 
-               status = asl_file_fetch_object(s, kv, &k, &len);
+               status = asl_file_fetch_object(s, ASL_FILE_TYPE_STR, kv, &k, &len);
                if (status != ASL_STATUS_OK)
                {
                        asl_msg_release(out);
                if (status != ASL_STATUS_OK)
                {
                        asl_msg_release(out);
@@ -1419,7 +1558,7 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, asl_msg_t **msg)
 
                if (kv != 0)
                {
 
                if (kv != 0)
                {
-                       status = asl_file_fetch_object(s, kv, &v, &len);
+                       status = asl_file_fetch_object(s, ASL_FILE_TYPE_STR, kv, &v, &len);
                        if (status != ASL_STATUS_OK)
                        {
                                free(k);
                        if (status != ASL_STATUS_OK)
                        {
                                free(k);
index 48ba6abdb73f62d0b827a3db862a19cb196e070d..6f634dfd225167fb39fe1fd5cca697d01b99740b 100644 (file)
@@ -9,7 +9,7 @@
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -17,7 +17,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
  * @APPLE_LICENSE_HEADER_END@
  */
 
@@ -38,6 +38,7 @@
 #include <asl_object.h>
 #include <asl_private.h>
 #include <asl_core.h>
 #include <asl_object.h>
 #include <asl_private.h>
 #include <asl_core.h>
+#include <asl_client.h>
 #include <sys/types.h>
 #include <libkern/OSAtomic.h>
 #include <asl_msg.h>
 #include <sys/types.h>
 #include <libkern/OSAtomic.h>
 #include <asl_msg.h>
 
 #define forever for(;;)
 
 
 #define forever for(;;)
 
-#define streq(A, B) (strcmp(A, B) == 0)
-#define streq_len(A, B, C) (strncmp(A, B, C) == 0)
-#define strneq(A, B) (strcmp(A, B) != 0)
-#define strcaseeq(A, B) (strcasecmp(A, B) == 0)
-#define strcaseneq(A, B) (strcasecmp(A, B) != 0)
-
 #ifndef ASL_QUERY_OP_FALSE
 #define ASL_QUERY_OP_FALSE 0
 #endif
 #ifndef ASL_QUERY_OP_FALSE
 #define ASL_QUERY_OP_FALSE 0
 #endif
@@ -221,21 +216,132 @@ _asl_msg_std_key(const char *s, uint32_t len)
 #pragma mark -
 #pragma mark asl_msg
 
 #pragma mark -
 #pragma mark asl_msg
 
-static asl_msg_t *
-_asl_msg_make_page(void)
+static uint32_t
+_slot_count(asl_msg_t *m)
 {
 {
-       int i;
-       asl_msg_t *out = (asl_msg_t *)calloc(1, sizeof(asl_msg_t));
+       if (m == NULL) return 0;
+       if (m->asl_type == ASL_TYPE_MSG) return ASL_MSG_KVO_MSG_SLOTS;
+       if (m->asl_type == ASL_TYPE_QUERY) return ASL_MSG_KVO_QUERY_SLOTS;
+       return 0;
+}
 
 
-       if (out == NULL) return NULL;
 
 
-       for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
+static uint16_t
+_get_slot_key(asl_msg_t *m, uint32_t slot)
+{
+       if (m == NULL) return 0;
+
+       if (m->asl_type == ASL_TYPE_MSG)
+       {
+               if (slot < ASL_MSG_KVO_MSG_SLOTS) return m->kvo[slot];
+               return 0;
+       }
+
+       if (m->asl_type == ASL_TYPE_QUERY)
+       {
+               if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot];
+               return 0;
+       }
+
+       return 0;
+}
+
+
+static void
+_set_slot_key(asl_msg_t *m, uint32_t slot, uint16_t x)
+{
+       if (m == NULL) return;
+
+       if (m->asl_type == ASL_TYPE_MSG)
+       {
+               if (slot < ASL_MSG_KVO_MSG_SLOTS) m->kvo[slot] = x;
+               return;
+       }
+
+       if (m->asl_type == ASL_TYPE_QUERY)
+       {
+               if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot] = x;
+               return;
+       }
+}
+
+
+static uint16_t
+_get_slot_val(asl_msg_t *m, uint32_t slot)
+{
+       if (m == NULL) return 0;
+       if (m->asl_type == ASL_TYPE_MSG)
+       {
+               if (slot < ASL_MSG_KVO_MSG_SLOTS) return m->kvo[slot + ASL_MSG_KVO_MSG_SLOTS];
+               return 0;
+       }
+
+       if (m->asl_type == ASL_TYPE_QUERY)
        {
        {
-               out->key[i] = ASL_MSG_SLOT_FREE;
-               out->val[i] = ASL_MSG_SLOT_FREE;
+               if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot + ASL_MSG_KVO_QUERY_SLOTS];
+               return 0;
        }
 
        }
 
+       return 0;
+}
+
+static void
+_set_slot_val(asl_msg_t *m, uint32_t slot, uint16_t x)
+{
+       if (m == NULL) return;
+
+       if (m->asl_type == ASL_TYPE_MSG)
+       {
+               if (slot < ASL_MSG_KVO_MSG_SLOTS) m->kvo[slot + ASL_MSG_KVO_MSG_SLOTS] = x;
+               return;
+       }
+
+       if (m->asl_type == ASL_TYPE_QUERY)
+       {
+               if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot + ASL_MSG_KVO_QUERY_SLOTS] = x;
+               return;
+       }
+}
+
+static uint16_t
+_get_slot_op(asl_msg_t *m, uint32_t slot)
+{
+       if (m == NULL) return 0;
+
+       if (m->asl_type == ASL_TYPE_QUERY)
+       {
+               if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot + (ASL_MSG_KVO_QUERY_SLOTS * 2)];
+               return 0;
+       }
+
+       return 0;
+}
+
+static void
+_set_slot_op(asl_msg_t *m, uint32_t slot, uint16_t x)
+{
+       if (m == NULL) return;
+
+       if (m->asl_type == ASL_TYPE_QUERY)
+       {
+               if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot + (ASL_MSG_KVO_QUERY_SLOTS * 2)] = x;
+       }
+}
+
+static asl_msg_t *
+_asl_msg_make_page(uint32_t type)
+{
+       uint32_t i, n = 0;
+       asl_msg_t *out = (asl_msg_t *)calloc(1, sizeof(asl_msg_t));
+       if (out == NULL) return NULL;
+
+       if (type == ASL_TYPE_MSG) n = ASL_MSG_KVO_MSG_SLOTS * 2;
+       else if (type == ASL_TYPE_QUERY) n = ASL_MSG_KVO_QUERY_SLOTS * 2;
+
+       for (i = 0; i < n; i++) out->kvo[i] = ASL_MSG_SLOT_FREE;
+
        out->mem_size = sizeof(asl_msg_t);
        out->mem_size = sizeof(asl_msg_t);
+       out->asl_type = type;
 
        return out;
 }
 
        return out;
 }
@@ -259,28 +365,33 @@ static const char *
 _asl_msg_slot_key(asl_msg_t *page, uint32_t slot)
 {
        const char *out;
 _asl_msg_slot_key(asl_msg_t *page, uint32_t slot)
 {
        const char *out;
-       uint16_t x;
+       uint16_t x, k;
 
        if (page == NULL) return NULL;
 
        if (page == NULL) return NULL;
-       if (slot >= ASL_MSG_PAGE_SLOTS) return NULL;
-       if (page->key[slot] == ASL_MSG_SLOT_FREE) return NULL;
 
 
-       switch (page->key[slot] & ASL_MSG_KV_MASK)
+       if ((page->asl_type == ASL_TYPE_MSG) && (slot >= ASL_MSG_KVO_MSG_SLOTS)) return NULL;
+       else if ((page->asl_type == ASL_TYPE_QUERY) && (slot >= ASL_MSG_KVO_QUERY_SLOTS)) return NULL;
+
+       k = _get_slot_key(page, slot);
+
+       if (k == ASL_MSG_SLOT_FREE) return NULL;
+
+       switch (k & ASL_MSG_KV_MASK)
        {
                case ASL_MSG_KV_INLINE:
                {
        {
                case ASL_MSG_KV_INLINE:
                {
-                       return page->data + page->key[slot];
+                       return page->data + k;
                }
                case ASL_MSG_KV_DICT:
                {
                }
                case ASL_MSG_KV_DICT:
                {
-                       if ((page->key[slot] > ASL_STD_KEY_BASE) && (page->key[slot] <= ASL_STD_KEY_LAST))
+                       if ((k > ASL_STD_KEY_BASE) && (k <= ASL_STD_KEY_LAST))
                        {
                        {
-                               x = page->key[slot] - ASL_STD_KEY_BASE - 1;
+                               x = k - ASL_STD_KEY_BASE - 1;
                                return ASLStandardKey[x];
                        }
                                return ASLStandardKey[x];
                        }
-                       else if ((page->key[slot] > ASL_MT_KEY_BASE) && (page->key[slot] <= ASL_MT_KEY_LAST))
+                       else if ((k > ASL_MT_KEY_BASE) && (k <= ASL_MT_KEY_LAST))
                        {
                        {
-                               x = page->key[slot] - ASL_MT_KEY_BASE - 1;
+                               x = k - ASL_MT_KEY_BASE - 1;
                                return MTStandardKey[x];
                        }
 
                                return MTStandardKey[x];
                        }
 
@@ -288,7 +399,7 @@ _asl_msg_slot_key(asl_msg_t *page, uint32_t slot)
                }
                case ASL_MSG_KV_EXTERN:
                {
                }
                case ASL_MSG_KV_EXTERN:
                {
-                       x = page->key[slot] & ASL_MSG_OFFSET_MASK;
+                       x = k & ASL_MSG_OFFSET_MASK;
                        memcpy(&out, page->data + x, sizeof(char *));
                        return out;
                }
                        memcpy(&out, page->data + x, sizeof(char *));
                        return out;
                }
@@ -301,22 +412,26 @@ static const char *
 _asl_msg_slot_val(asl_msg_t *page, uint32_t slot)
 {
        const char *out;
 _asl_msg_slot_val(asl_msg_t *page, uint32_t slot)
 {
        const char *out;
-       uint16_t x, type;
+       uint16_t x, v, type;
 
        if (page == NULL) return NULL;
 
        if (page == NULL) return NULL;
-       if (slot >= ASL_MSG_PAGE_SLOTS) return NULL;
 
 
-       if (page->val[slot] == ASL_MSG_SLOT_FREE) return NULL;
+       if ((page->asl_type == ASL_TYPE_MSG) && (slot >= ASL_MSG_KVO_MSG_SLOTS)) return NULL;
+       else if ((page->asl_type == ASL_TYPE_QUERY) && (slot >= ASL_MSG_KVO_QUERY_SLOTS)) return NULL;
 
 
-       type = page->val[slot] & ASL_MSG_KV_MASK;
+       v = _get_slot_val(page, slot);
+
+       if (v == ASL_MSG_SLOT_FREE) return NULL;
+
+       type = v & ASL_MSG_KV_MASK;
 
        if (type == ASL_MSG_KV_INLINE)
        {
 
        if (type == ASL_MSG_KV_INLINE)
        {
-               return page->data + page->val[slot];
+               return page->data + v;
        }
        else if (type == ASL_MSG_KV_EXTERN)
        {
        }
        else if (type == ASL_MSG_KV_EXTERN)
        {
-               x = page->val[slot] & ASL_MSG_OFFSET_MASK;
+               x = v & ASL_MSG_OFFSET_MASK;
                memcpy(&out, page->data + x, sizeof(char *));
                return out;
        }
                memcpy(&out, page->data + x, sizeof(char *));
                return out;
        }
@@ -332,7 +447,7 @@ asl_msg_new(uint32_t type)
 {
        asl_msg_t *out;
 
 {
        asl_msg_t *out;
 
-       out = _asl_msg_make_page();
+       out = _asl_msg_make_page(type);
        if (out == NULL) return NULL;
 
        out->asl_type = type;
        if (out == NULL) return NULL;
 
        out->asl_type = type;
@@ -344,28 +459,33 @@ asl_msg_new(uint32_t type)
 static void
 _asl_msg_free_page(asl_msg_t *page)
 {
 static void
 _asl_msg_free_page(asl_msg_t *page)
 {
-       uint32_t i;
+       uint32_t i, mslots;
        char *p;
 
        if (page == NULL) return;
 
        char *p;
 
        if (page == NULL) return;
 
-       for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
+       mslots = _slot_count(page);
+
+       for (i = 0; i < mslots; i++)
        {
        {
-               if (page->key[i] == ASL_STD_KEY_FREE_NOTE)
+               uint16_t k = _get_slot_key(page, i);
+               uint16_t v = _get_slot_val(page, i);
+
+               if (k == ASL_STD_KEY_FREE_NOTE)
                {
                        const char *x = _asl_msg_slot_val(page, i);
                        if (x != NULL) notify_post(x);
                }
 
                {
                        const char *x = _asl_msg_slot_val(page, i);
                        if (x != NULL) notify_post(x);
                }
 
-               if ((page->key[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+               if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
                {
                {
-                       memcpy(&p, page->data + (page->key[i] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+                       memcpy(&p, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *));
                        free(p);
                }
 
                        free(p);
                }
 
-               if ((page->val[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+               if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
                {
                {
-                       memcpy(&p, page->data + (page->val[i] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+                       memcpy(&p, page->data + (v & ASL_MSG_OFFSET_MASK), sizeof(char *));
                        free(p);
                }
        }
                        free(p);
                }
        }
@@ -456,7 +576,7 @@ _asl_msg_dump_kv(FILE *f, asl_msg_t *msg, uint16_t x)
 void
 _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg)
 {
 void
 _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg)
 {
-       int i, page1 = 1;
+       uint32_t i, mslots, page1 = 1;
 
        if (f == NULL) return;
        if (msg == NULL)
 
        if (f == NULL) return;
        if (msg == NULL)
@@ -465,6 +585,8 @@ _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg)
                return;
        }
 
                return;
        }
 
+       mslots = _slot_count(msg);
+
        while (msg != NULL)
        {
                if (page1 == 1)
        while (msg != NULL)
        {
                if (page1 == 1)
@@ -484,13 +606,13 @@ _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg)
                fprintf(f, "    mem_size: %llu\n", msg->mem_size);
                fprintf(f, "    next: %p\n", msg->next);
 
                fprintf(f, "    mem_size: %llu\n", msg->mem_size);
                fprintf(f, "    next: %p\n", msg->next);
 
-               for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
+               for (i = 0; i < mslots; i++)
                {
                        fprintf(f, "    slot[%d]: ", i);
                {
                        fprintf(f, "    slot[%d]: ", i);
-                       _asl_msg_dump_kv(f, msg, msg->key[i]);
+                       _asl_msg_dump_kv(f, msg, _get_slot_key(msg, i));
                        fprintf(f, " ");
                        fprintf(f, " ");
-                       _asl_msg_dump_kv(f, msg, msg->val[i]);
-                       fprintf(f, " 0x%04x\n", msg->op[i]);
+                       _asl_msg_dump_kv(f, msg, _get_slot_val(msg, i));
+                       if (msg->asl_type == ASL_TYPE_QUERY) fprintf(f, " 0x%04x\n", _get_slot_op(msg, i));
                }
 
                msg = msg->next;
                }
 
                msg = msg->next;
@@ -506,7 +628,7 @@ _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg)
 static uint32_t
 _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opage)
 {
 static uint32_t
 _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opage)
 {
-       uint32_t i, len, slot;
+       uint32_t i, len, slot, mslots;
        uint16_t kx;
        asl_msg_t *page;
        const char *kp;
        uint16_t kx;
        asl_msg_t *page;
        const char *kp;
@@ -516,6 +638,8 @@ _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opa
 
        i = 0;
        slot = 0;
 
        i = 0;
        slot = 0;
+       mslots = _slot_count(msg);
+
        if (oslot != NULL) *oslot = slot;
 
        page = msg;
        if (oslot != NULL) *oslot = slot;
 
        page = msg;
@@ -526,24 +650,24 @@ _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opa
 
        forever
        {
 
        forever
        {
-               if (page->key[slot] != ASL_MSG_SLOT_FREE)
+               if (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE)
                {
                        if (kx != 0)
                        {
                {
                        if (kx != 0)
                        {
-                               if (page->key[slot] == kx) return i;
+                               if (_get_slot_key(page, slot) == kx) return i;
                        }
                        }
-                       else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT)
+                       else if ((_get_slot_key(page, slot) & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT)
                        {
                        {
-                               /* page->key[slot] is a dictionary key, but key is not (kx == 0) so skip this slot */
+                               /* _get_slot_key(page, slot) is a dictionary key, but key is not (kx == 0) so skip this slot */
                        }
                        }
-                       else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+                       else if ((_get_slot_key(page, slot) & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
                        {
                        {
-                               memcpy(&kp, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+                               memcpy(&kp, page->data + (_get_slot_key(page, slot) & ASL_MSG_OFFSET_MASK), sizeof(char *));
                                if (streq(key, kp)) return i;
                        }
                        else
                        {
                                if (streq(key, kp)) return i;
                        }
                        else
                        {
-                               kp = page->data + page->key[slot];
+                               kp = page->data + _get_slot_key(page, slot);
                                if (streq(key, kp)) return i;
                        }
                }
                                if (streq(key, kp)) return i;
                        }
                }
@@ -552,7 +676,7 @@ _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opa
                slot++;
                if (oslot != NULL) *oslot = slot;
 
                slot++;
                if (oslot != NULL) *oslot = slot;
 
-               if (slot >= ASL_MSG_PAGE_SLOTS)
+               if (slot >= mslots)
                {
                        if (page->next == NULL) return IndexNull;
 
                {
                        if (page->next == NULL) return IndexNull;
 
@@ -573,7 +697,7 @@ _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opa
 static int
 _asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *slot)
 {
 static int
 _asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *slot)
 {
-       uint32_t i, sx;
+       uint32_t i, sx, mslots;
        asl_msg_t *px;
 
        if (msg == NULL) return -1;
        asl_msg_t *px;
 
        if (msg == NULL) return -1;
@@ -581,6 +705,8 @@ _asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *s
        *slot = IndexNull;
        *page = NULL;
 
        *slot = IndexNull;
        *page = NULL;
 
+       mslots = _slot_count(msg);
+
        sx = 0;
 
        /* find page */
        sx = 0;
 
        /* find page */
@@ -595,9 +721,9 @@ _asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *s
                *page = px;
 
                /* find slot */
                *page = px;
 
                /* find slot */
-               for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
+               for (i = 0; i < mslots; i++)
                {
                {
-                       if (px->key[i] != ASL_MSG_SLOT_FREE)
+                       if (px->kvo[i] != ASL_MSG_SLOT_FREE)
                        {
                                if (sx == n)
                                {
                        {
                                if (sx == n)
                                {
@@ -614,7 +740,7 @@ _asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *s
 }
 
 /*
 }
 
 /*
- * asl_msg_fetch: iterate over entries 
+ * asl_msg_fetch: iterate over entries
  * initial value of n should be 0.  Subseqent calls should use the last
  * returned value.  Returns IndexNull when there are no more entries
  * Sets the pointers for the next key, value, and op in the msg.
  * initial value of n should be 0.  Subseqent calls should use the last
  * returned value.  Returns IndexNull when there are no more entries
  * Sets the pointers for the next key, value, and op in the msg.
@@ -624,11 +750,13 @@ _asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *s
 uint32_t
 asl_msg_fetch(asl_msg_t *msg, uint32_t x, const char **keyout, const char **valout, uint16_t *opout)
 {
 uint32_t
 asl_msg_fetch(asl_msg_t *msg, uint32_t x, const char **keyout, const char **valout, uint16_t *opout)
 {
-       uint32_t p, xpn, xsn;
+       uint32_t p, xpn, xsn, mslots;
        asl_msg_t *page = NULL;
 
        if (msg == NULL) return IndexNull;
 
        asl_msg_t *page = NULL;
 
        if (msg == NULL) return IndexNull;
 
+       mslots = _slot_count(msg);
+
        xsn = x >> 24;
        xpn = x & 0x00ffffff;
 
        xsn = x >> 24;
        xpn = x & 0x00ffffff;
 
@@ -644,14 +772,14 @@ asl_msg_fetch(asl_msg_t *msg, uint32_t x, const char **keyout, const char **valo
 
        if (keyout != NULL) *keyout = _asl_msg_slot_key(page, xsn);
        if (valout != NULL) *valout = _asl_msg_slot_val(page, xsn);
 
        if (keyout != NULL) *keyout = _asl_msg_slot_key(page, xsn);
        if (valout != NULL) *valout = _asl_msg_slot_val(page, xsn);
-       if (opout != NULL) *opout = (uint32_t)(page->op[xsn]);
+       if (opout != NULL) *opout = _get_slot_op(page, xsn);
 
        /* advance to the next slot */
        forever
        {
                xsn++;
 
 
        /* advance to the next slot */
        forever
        {
                xsn++;
 
-               if (xsn >= ASL_MSG_PAGE_SLOTS)
+               if (xsn >= mslots)
                {
                        if (page->next == NULL) return 0xff000000;
                        xsn = 0;
                {
                        if (page->next == NULL) return 0xff000000;
                        xsn = 0;
@@ -659,7 +787,7 @@ asl_msg_fetch(asl_msg_t *msg, uint32_t x, const char **keyout, const char **valo
                        xpn++;
                }
 
                        xpn++;
                }
 
-               if (page->key[xsn] != ASL_MSG_SLOT_FREE) return ((xsn << 24) | xpn);
+               if (page->kvo[xsn] != ASL_MSG_SLOT_FREE) return ((xsn << 24) | xpn);
        }
 
        return IndexNull;
        }
 
        return IndexNull;
@@ -682,7 +810,7 @@ asl_msg_lookup(asl_msg_t *msg, const char *key, const char **valout, uint16_t *o
        if (i == IndexNull) return -1;
 
        if (valout != NULL) *valout = _asl_msg_slot_val(page, slot);
        if (i == IndexNull) return -1;
 
        if (valout != NULL) *valout = _asl_msg_slot_val(page, slot);
-       if (opout != NULL) *opout = (uint32_t)(page->op[slot]);
+       if (opout != NULL) *opout = _get_slot_op(page, slot);
 
        return 0;
 }
 
        return 0;
 }
@@ -706,17 +834,19 @@ asl_msg_get_val_for_key(asl_msg_t *msg, const char *key)
 const char *
 asl_msg_key(asl_msg_t *msg, uint32_t n)
 {
 const char *
 asl_msg_key(asl_msg_t *msg, uint32_t n)
 {
-       uint32_t slot, i;
+       uint32_t slot, i, mslots;
        asl_msg_t *page;
 
        if (msg == NULL) return NULL;
 
        asl_msg_t *page;
 
        if (msg == NULL) return NULL;
 
+       mslots = _slot_count(msg);
+
        i = 0;
        for (page = msg; page != NULL; page = page->next)
        {
        i = 0;
        for (page = msg; page != NULL; page = page->next)
        {
-               for (slot = 0; slot < ASL_MSG_PAGE_SLOTS; slot++)
+               for (slot = 0; slot < mslots; slot++)
                {
                {
-                       if (page->key[slot] != ASL_MSG_SLOT_FREE)
+                       if (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE)
                        {
                                if (i == n) return _asl_msg_slot_key(page, slot);
                                i++;
                        {
                                if (i == n) return _asl_msg_slot_key(page, slot);
                                i++;
@@ -733,15 +863,18 @@ asl_msg_key(asl_msg_t *msg, uint32_t n)
 static int
 _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
 {
 static int
 _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
 {
-       uint32_t slot, keylen, vallen, total;
+       uint32_t slot, keylen, vallen, total, mslots;
        uint64_t klen, vlen;
        uint64_t klen, vlen;
-       uint16_t kx;
+       uint16_t kx, k, v, o;
        asl_msg_t *page, *last;
        char *extkey, *extval;
 
        if (msg == NULL) return -1;
        if (key == NULL) return -1;
 
        asl_msg_t *page, *last;
        char *extkey, *extval;
 
        if (msg == NULL) return -1;
        if (key == NULL) return -1;
 
+       mslots = _slot_count(msg);
+
+       o = op;
        extkey = NULL;
        extval = NULL;
 
        extkey = NULL;
        extval = NULL;
 
@@ -809,15 +942,15 @@ _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32
                if (total <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size))
                {
                        /* check for a free slot */
                if (total <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size))
                {
                        /* check for a free slot */
-                       for (slot = 0; (slot < ASL_MSG_PAGE_SLOTS) && (page->key[slot] != ASL_MSG_SLOT_FREE); slot++);
-                       if (slot < ASL_MSG_PAGE_SLOTS) break;
+                       for (slot = 0; (slot < mslots) && (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE); slot++);
+                       if (slot < mslots) break;
                }
        }
 
        if (page == NULL)
        {
                /* allocate a new page and attach it */
                }
        }
 
        if (page == NULL)
        {
                /* allocate a new page and attach it */
-               page = _asl_msg_make_page();
+               page = _asl_msg_make_page(msg->asl_type);
                if (page == NULL)
                {
                        if (extkey != NULL) free(extkey);
                if (page == NULL)
                {
                        if (extkey != NULL) free(extkey);
@@ -832,44 +965,47 @@ _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32
        /* copy key or external key pointer into page data */
        if (kx != 0)
        {
        /* copy key or external key pointer into page data */
        if (kx != 0)
        {
-               page->key[slot] = kx;
+               k = kx;
        }
        else if (extkey == NULL)
        {
        }
        else if (extkey == NULL)
        {
-               page->key[slot] = page->data_size;
+               k = page->data_size;
                memcpy(page->data + page->data_size, key, keylen);
        }
        else
        {
                memcpy(page->data + page->data_size, key, keylen);
        }
        else
        {
-               page->key[slot] = page->data_size | ASL_MSG_KV_EXTERN;
+               k = page->data_size | ASL_MSG_KV_EXTERN;
                memcpy(page->data + page->data_size, &extkey, keylen);
                page->mem_size += klen;
        }
 
                memcpy(page->data + page->data_size, &extkey, keylen);
                page->mem_size += klen;
        }
 
+       _set_slot_key(page, slot, k);
        page->data_size += keylen;
 
        /* copy val or external val pointer into page data */
        page->data_size += keylen;
 
        /* copy val or external val pointer into page data */
-       page->val[slot] = ASL_MSG_SLOT_FREE;
+
+       v = ASL_MSG_SLOT_FREE;
 
        if (val != NULL)
        {
                if (extval == NULL)
                {
 
        if (val != NULL)
        {
                if (extval == NULL)
                {
-                       page->val[slot] = page->data_size;
+                       v = page->data_size;
                        memcpy(page->data + page->data_size, val, vallen);
                }
                else
                {
                        memcpy(page->data + page->data_size, val, vallen);
                }
                else
                {
-                       page->val[slot] = page->data_size | ASL_MSG_KV_EXTERN;
+                       v = page->data_size | ASL_MSG_KV_EXTERN;
                        memcpy(page->data + page->data_size, &extval, vallen);
                        page->mem_size += vlen;
                }
 
                        memcpy(page->data + page->data_size, &extval, vallen);
                        page->mem_size += vlen;
                }
 
+               _set_slot_val(page, slot, v);
                page->data_size += vallen;
        }
 
        /* set op */
                page->data_size += vallen;
        }
 
        /* set op */
-       page->op[slot] = (uint16_t)op;
+       _set_slot_op(page, slot, o);
 
        /* update page count */
        page->count++;
 
        /* update page count */
        page->count++;
@@ -888,17 +1024,22 @@ _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32
 static int
 _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
 {
 static int
 _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
 {
-       uint32_t i, slot, newexternal;
+       uint32_t i, slot, mslots, newexternal;
        asl_msg_t *page;
        uint32_t intvallen, extvallen, newvallen;
        char *intval, *extval, *newval;
        asl_msg_t *page;
        uint32_t intvallen, extvallen, newvallen;
        char *intval, *extval, *newval;
+       uint16_t k, v, o;
 
        if (msg == NULL) return -1;
        if (key == NULL) return -1;
 
 
        if (msg == NULL) return -1;
        if (key == NULL) return -1;
 
+       mslots = _slot_count(msg);
+
        slot = IndexNull;
        page = NULL;
 
        slot = IndexNull;
        page = NULL;
 
+       o = op;
+
        if ((msg->asl_type == ASL_TYPE_QUERY) || (IndexNull == _asl_msg_index(msg, key, &slot, &page)))
        {
                /* add key */
        if ((msg->asl_type == ASL_TYPE_QUERY) || (IndexNull == _asl_msg_index(msg, key, &slot, &page)))
        {
                /* add key */
@@ -911,17 +1052,19 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
        extval = NULL;
        extvallen = 0;
 
        extval = NULL;
        extvallen = 0;
 
-       if (page->val[slot] != ASL_MSG_SLOT_FREE)
+       v = _get_slot_val(page, slot);
+
+       if (v != ASL_MSG_SLOT_FREE)
        {
        {
-               if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+               if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
                {
                {
-                       i = page->val[slot] & ASL_MSG_OFFSET_MASK;
+                       i = v & ASL_MSG_OFFSET_MASK;
                        memcpy(&extval, page->data + i, sizeof(char *));
                        extvallen = sizeof(char *);
                }
                else
                {
                        memcpy(&extval, page->data + i, sizeof(char *));
                        extvallen = sizeof(char *);
                }
                else
                {
-                       intval = page->data + page->val[slot];
+                       intval = page->data + v;
                        intvallen = strlen(intval) + 1;
                }
        }
                        intvallen = strlen(intval) + 1;
                }
        }
@@ -937,41 +1080,41 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
                        free(extval);
                }
 
                        free(extval);
                }
 
-               page->val[slot] = ASL_MSG_SLOT_FREE;
-               if (op != IndexNull) page->op[slot] = (uint16_t)op;
+               _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
+               if (op != IndexNull) _set_slot_op(page, slot, o);
                return 0;
        }
 
        /* trivial case - internal val doesn't change */
        if ((intval != NULL) && (streq(val, intval)))
        {
                return 0;
        }
 
        /* trivial case - internal val doesn't change */
        if ((intval != NULL) && (streq(val, intval)))
        {
-               if (op != IndexNull) page->op[slot] = (uint16_t)op;
+               if (op != IndexNull) _set_slot_op(page, slot, o);
                return 0;
        }
 
        /* trivial case - external val doesn't change */
        if ((extval != NULL) && (streq(val, extval)))
        {
                return 0;
        }
 
        /* trivial case - external val doesn't change */
        if ((extval != NULL) && (streq(val, extval)))
        {
-               if (op != IndexNull) page->op[slot] = (uint16_t)op;
+               if (op != IndexNull) _set_slot_op(page, slot, o);
                return 0;
        }
 
        /*
         * special case: we generally don't compress out holes in the data
         * space, but if this is the last string in the currently used data space
                return 0;
        }
 
        /*
         * special case: we generally don't compress out holes in the data
         * space, but if this is the last string in the currently used data space
-        * we can just back up the data_size and reset page->val[slot]
+        * we can just back up the data_size and reset page->val[slot] (a.k.a. page->kvo[slot + mslots])
         */
         */
-       i = page->val[slot] & ASL_MSG_OFFSET_MASK;
+       i = v & ASL_MSG_OFFSET_MASK;
        if ((intval != NULL) && ((i + intvallen) == page->data_size))
        {
        if ((intval != NULL) && ((i + intvallen) == page->data_size))
        {
-               page->val[slot] = ASL_MSG_SLOT_FREE;
+               _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
                page->data_size -= intvallen;
                intval = NULL;
                intvallen = 0;
        }
        else if ((extval != NULL) && ((i + extvallen) == page->data_size))
        {
                page->data_size -= intvallen;
                intval = NULL;
                intvallen = 0;
        }
        else if ((extval != NULL) && ((i + extvallen) == page->data_size))
        {
-               page->val[slot] = ASL_MSG_SLOT_FREE;
+               _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
                page->data_size -= extvallen;
                page->mem_size -= (strlen(extval) + 1);
                free(extval);
                page->data_size -= extvallen;
                page->mem_size -= (strlen(extval) + 1);
                free(extval);
@@ -1001,7 +1144,7 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
                extval = NULL;
 
                /* we can re-use the space of the old value */
                extval = NULL;
 
                /* we can re-use the space of the old value */
-               i = page->val[slot] & ASL_MSG_OFFSET_MASK;
+               i = v & ASL_MSG_OFFSET_MASK;
 
                if (newexternal == 1)
                {
 
                if (newexternal == 1)
                {
@@ -1010,17 +1153,17 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
                        if (newval == NULL) return -1;
 
                        page->mem_size += (strlen(newval) + 1);
                        if (newval == NULL) return -1;
 
                        page->mem_size += (strlen(newval) + 1);
-                       page->val[slot] = i | ASL_MSG_KV_EXTERN;
+                       _set_slot_val(page, slot, i | ASL_MSG_KV_EXTERN);
                        memcpy(page->data + i, &newval, sizeof(char *));
                }
                else
                {
                        /* new internal value */
                        memcpy(page->data + i, &newval, sizeof(char *));
                }
                else
                {
                        /* new internal value */
-                       page->val[slot] = i;
+                       _set_slot_val(page, slot, i);
                        memcpy(page->data + i, val, newvallen);
                }
 
                        memcpy(page->data + i, val, newvallen);
                }
 
-               if (op != IndexNull) page->op[slot] = (uint16_t)op;
+               if (op != IndexNull) _set_slot_op(page, slot, o);
                return 0;
        }
 
                return 0;
        }
 
@@ -1046,32 +1189,32 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
                        if (newval == NULL) return -1;
 
                        page->mem_size += (strlen(newval) + 1);
                        if (newval == NULL) return -1;
 
                        page->mem_size += (strlen(newval) + 1);
-                       page->val[slot] = i | ASL_MSG_KV_EXTERN;
+                       _set_slot_val(page, slot, i | ASL_MSG_KV_EXTERN);
                        memcpy(page->data + i, &newval, sizeof(char *));
                }
                else
                {
                        /* new internal value */
                        memcpy(page->data + i, &newval, sizeof(char *));
                }
                else
                {
                        /* new internal value */
-                       page->val[slot] = i;
+                       _set_slot_val(page, slot, i);
                        memcpy(page->data + i, val, newvallen);
                }
 
                        memcpy(page->data + i, val, newvallen);
                }
 
-               if (op != IndexNull) page->op[slot] = (uint16_t)op;
+               if (op != IndexNull) _set_slot_op(page, slot, o);
                return 0;
 
        }
 
        /* no room on this page - free up existing entry and treat this as a new entry */
                return 0;
 
        }
 
        /* no room on this page - free up existing entry and treat this as a new entry */
-       if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+       if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
        {
        {
-               memcpy(&extval, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+               memcpy(&extval, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *));
                page->mem_size -= (strlen(extval) + 1);
                free(extval);
        }
 
                page->mem_size -= (strlen(extval) + 1);
                free(extval);
        }
 
-       page->key[slot] = ASL_MSG_SLOT_FREE;
-       page->val[slot] = ASL_MSG_SLOT_FREE;
-       page->op[slot] = 0;
+       _set_slot_key(page, slot, ASL_MSG_SLOT_FREE);
+       _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
+       _set_slot_op(page, slot, 0);
 
        return _asl_msg_new_key_val_op(msg, key, val, op);
 }
 
        return _asl_msg_new_key_val_op(msg, key, val, op);
 }
@@ -1083,6 +1226,9 @@ asl_msg_set_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_
        uint32_t i, len;
        int status;
 
        uint32_t i, len;
        int status;
 
+       if (msg == NULL) return -1;
+       if (key == NULL) return -1;
+
        /* Special case handling */
        special = NULL;
 
        /* Special case handling */
        special = NULL;
 
@@ -1148,28 +1294,34 @@ static void
 _asl_msg_unset_page_slot(asl_msg_t *page, uint32_t slot)
 {
        char *ext;
 _asl_msg_unset_page_slot(asl_msg_t *page, uint32_t slot)
 {
        char *ext;
+       uint16_t k, v;
 
        if (page == NULL) return;
 
        if (page == NULL) return;
-       if (slot >= ASL_MSG_PAGE_SLOTS) return;
-       if (page->key[slot] == ASL_MSG_SLOT_FREE) return;
 
 
-       if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+       if (slot >= _slot_count(page)) return;
+
+       k = _get_slot_key(page, slot);
+       v = _get_slot_val(page, slot);
+
+       if (k == ASL_MSG_SLOT_FREE) return;
+
+       if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
        {
        {
-               memcpy(&ext, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+               memcpy(&ext, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *));
                page->mem_size -= (strlen(ext) + 1);
                free(ext);
        }
 
                page->mem_size -= (strlen(ext) + 1);
                free(ext);
        }
 
-       if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+       if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
        {
        {
-               memcpy(&ext, page->data + (page->val[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+               memcpy(&ext, page->data + (v & ASL_MSG_OFFSET_MASK), sizeof(char *));
                page->mem_size -= (strlen(ext) + 1);
                free(ext);
        }
 
                page->mem_size -= (strlen(ext) + 1);
                free(ext);
        }
 
-       page->key[slot] = ASL_MSG_SLOT_FREE;
-       page->val[slot] = ASL_MSG_SLOT_FREE;
-       page->op[slot] = 0;
+       _set_slot_key(page, slot, ASL_MSG_SLOT_FREE);
+       _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
+       _set_slot_op(page, slot, 0);
 
        page->count--;
 }
 
        page->count--;
 }
@@ -1798,8 +1950,8 @@ _asl_time_string(const char *infmt, const char *str, const char *nano)
                off %= 3600;
                zm = off / 60;
 
                off %= 3600;
                zm = off / 60;
 
-               if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh);
-               else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm);
+               if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh);
+               else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm);
 
                asprintf(&out, "%d-%02d-%02d%c%02d:%02d:%02d%s%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, sep, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, zstr);
                return out;
 
                asprintf(&out, "%d-%02d-%02d%c%02d:%02d:%02d%s%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, sep, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, zstr);
                return out;
@@ -1815,8 +1967,8 @@ _asl_time_string(const char *infmt, const char *str, const char *nano)
                off %= 3600;
                zm = off / 60;
 
                off %= 3600;
                zm = off / 60;
 
-               if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh);
-               else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm);
+               if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh);
+               else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm);
 
                asprintf(&out, "%d%02d%02dT%02d%02d%02d%s%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, zstr);
                return out;
 
                asprintf(&out, "%d%02d%02dT%02d%02d%02d%s%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, zstr);
                return out;
@@ -1824,7 +1976,7 @@ _asl_time_string(const char *infmt, const char *str, const char *nano)
 
        if ((!strcasecmp(fmt, "sec")) || (!strcasecmp(fmt, "raw")))
        {
 
        if ((!strcasecmp(fmt, "sec")) || (!strcasecmp(fmt, "raw")))
        {
-               asprintf(&out, "%lu%s", tick, nanobuf);
+               asprintf(&out, "%llu%s", (unsigned long long) tick, nanobuf);
                return out;
        }
 
                return out;
        }
 
@@ -1882,8 +2034,8 @@ _asl_time_string(const char *infmt, const char *str, const char *nano)
                off = (zh * 3600) + (zm * 60);
                if (neg) off *= -1;
 
                off = (zh * 3600) + (zm * 60);
                if (neg) off *= -1;
 
-               if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh);
-               else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm);
+               if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh);
+               else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm);
        }
 
 
        }
 
 
@@ -2879,6 +3031,114 @@ asl_format_message(asl_msg_t *msg, const char *mfmt, const char *tfmt, uint32_t
        return out;
 }
 
        return out;
 }
 
+#pragma mark -
+#pragma mark xpc conversion
+
+static void
+_asl_msg_to_xpc(asl_msg_t *msg, xpc_object_t dict)
+{
+       uint32_t x, len;
+       const char *key, *val, *nano;
+       uint16_t kx;
+
+       if (msg == NULL) return;
+       if (dict == NULL) return;
+
+       nano = NULL;
+       asl_msg_lookup(msg, ASL_KEY_TIME_NSEC, &nano, NULL);
+
+       for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL))
+       {
+               if (key == NULL) continue;
+
+               len = strlen(key);
+               kx = _asl_msg_std_key(key, len);
+
+               if (val == NULL)
+               {
+                       xpc_object_t obj = xpc_null_create();
+                       xpc_dictionary_set_value(dict, key, obj);
+                       xpc_release(obj);
+               }
+               else if (kx == 0)
+               {
+                       if (streq(key, ASL_KEY_SENDER_MACH_UUID))
+                       {
+                               uuid_t v;
+                               if (uuid_parse(val, v) == 0)
+                               {
+                                       xpc_object_t obj = xpc_uuid_create(v);
+                                       xpc_dictionary_set_value(dict, key, obj);
+                                       xpc_release(obj);
+                               }
+                       }
+                       else
+                       {
+                               xpc_object_t obj = xpc_string_create(val);
+                               xpc_dictionary_set_value(dict, key, obj);
+                               xpc_release(obj);
+                       }
+               }
+               else if (kx == ASL_STD_KEY_TIME)
+               {
+                       uint64_t t = NSEC_PER_SEC * asl_core_parse_time(val, NULL);
+                       if (nano != NULL) t += atoll(nano);
+                       xpc_object_t obj = xpc_date_create(t);
+                       xpc_dictionary_set_value(dict, key, obj);
+                       xpc_release(obj);
+               }
+               else if (kx == ASL_STD_KEY_NANO)
+               {
+                       /* handled with ASL_STD_KEY_TIME */
+               }
+               else if ((kx == ASL_STD_KEY_PID) || (kx == ASL_STD_KEY_REF_PID))
+               {
+                       int64_t v = atoll(val);
+                       xpc_object_t obj = xpc_int64_create(v);
+                       xpc_dictionary_set_value(dict, key, obj);
+                       xpc_release(obj);
+               }
+               else if ((kx == ASL_STD_KEY_UID) || (kx == ASL_STD_KEY_GID))
+               {
+                       int64_t v = atoll(val);
+                       xpc_object_t obj = xpc_int64_create(v);
+                       xpc_dictionary_set_value(dict, key, obj);
+                       xpc_release(obj);
+               }
+               else if (kx == ASL_STD_KEY_LEVEL)
+               {
+                       int64_t v = atoll(val);
+                       xpc_object_t obj = xpc_int64_create(v);
+                       xpc_dictionary_set_value(dict, key, obj);
+                       xpc_release(obj);
+               }
+               else if ((kx == ASL_STD_KEY_READ_UID) || (kx == ASL_STD_KEY_READ_GID))
+               {
+                       int64_t v = atoll(val);
+                       xpc_object_t obj = xpc_int64_create(v);
+                       xpc_dictionary_set_value(dict, key, obj);
+                       xpc_release(obj);
+               }
+               else if (kx == ASL_STD_KEY_MSG_ID)
+               {
+                       /* ignore */
+               }
+               else
+               {
+                       xpc_object_t obj = xpc_string_create(val);
+                       xpc_dictionary_set_value(dict, key, obj);
+                       xpc_release(obj);
+               }
+       }
+}
+
+void
+_asl_log_args_to_xpc(asl_object_t client, asl_object_t msg, xpc_object_t dict)
+{
+       _asl_msg_to_xpc(asl_client_kvdict((asl_client_t *)client), dict);
+       _asl_msg_to_xpc((asl_msg_t *)msg, dict);
+}
+
 #pragma mark -
 #pragma mark asl_object support
 
 #pragma mark -
 #pragma mark asl_object support
 
@@ -2930,7 +3190,8 @@ _jump_get_key_val_op_at_index(asl_object_private_t *obj, size_t n, const char **
 
        if (key != NULL) *key = _asl_msg_slot_key(page, slot);
        if (val != NULL) *val = _asl_msg_slot_val(page, slot);
 
        if (key != NULL) *key = _asl_msg_slot_key(page, slot);
        if (val != NULL) *val = _asl_msg_slot_val(page, slot);
-       if (op != NULL) *op = page->op[slot];
+       if (op != NULL) *op = _get_slot_op(page, slot);
+
        return 0;
 }
 
        return 0;
 }
 
index 39286bff4b9cf68b29e673a489da1ce864eeada9..e09032e523dd204d6bfe46fdabc281675586daf3 100644 (file)
@@ -161,7 +161,7 @@ asl_object_remove_object_at_index(asl_object_private_t *obj, size_t n)
 void
 asl_object_append(asl_object_private_t *obj, asl_object_private_t *newobj)
 {
 void
 asl_object_append(asl_object_private_t *obj, asl_object_private_t *newobj)
 {
-       int type = ASL_TYPE_CLIENT;
+       uint32_t type = ASL_TYPE_CLIENT;
 
        if (obj != NULL) type = obj->asl_type;
        if (type >= ASL_TYPE_COUNT) return;
 
        if (obj != NULL) type = obj->asl_type;
        if (type >= ASL_TYPE_COUNT) return;
index 08da1a1d992a022343b14ee9b5cc89a3e2b40942..b03dbb665946b568de8fccb2d99fcc86d043ea07 100644 (file)
@@ -91,7 +91,7 @@ asl_store_open_write(const char *basedir, asl_store_t **s)
        asl_store_t *out;
        struct stat sb;
        uint32_t i, flags;
        asl_store_t *out;
        struct stat sb;
        uint32_t i, flags;
-       char *path;
+       char path[MAXPATHLEN];
        FILE *sd;
        uint64_t last_id;
        time_t start;
        FILE *sd;
        uint64_t last_id;
        time_t start;
@@ -104,26 +104,26 @@ asl_store_open_write(const char *basedir, asl_store_t **s)
        if (basedir == NULL) basedir = PATH_ASL_STORE;
 
        memset(&sb, 0, sizeof(struct stat));
        if (basedir == NULL) basedir = PATH_ASL_STORE;
 
        memset(&sb, 0, sizeof(struct stat));
-       if (stat(basedir, &sb) != 0) return ASL_STATUS_INVALID_STORE;
-       if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE;
-
-       path = NULL;
-       asprintf(&path, "%s/%s", basedir, FILE_ASL_STORE_DATA);
-       if (path == NULL) return ASL_STATUS_NO_MEMORY;
+       if (stat(basedir, &sb) != 0)
+       {
+               if (errno != ENOENT) return ASL_STATUS_INVALID_STORE;
+               if (mkdir(basedir, 0755) != 0) return ASL_STATUS_WRITE_FAILED;
+       }
+       else
+       {
+               if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE;
+       }
+       
+       snprintf(path, sizeof(path), "%s/%s", basedir, FILE_ASL_STORE_DATA);
 
        sd = NULL;
 
        memset(&sb, 0, sizeof(struct stat));
        if (stat(path, &sb) != 0)
        {
 
        sd = NULL;
 
        memset(&sb, 0, sizeof(struct stat));
        if (stat(path, &sb) != 0)
        {
-               if (errno != ENOENT)
-               {
-                       free(path);
-                       return ASL_STATUS_FAILED;
-               }
+               if (errno != ENOENT) return ASL_STATUS_FAILED;
 
                sd = fopen(path, "w+");
 
                sd = fopen(path, "w+");
-               free(path);
 
                if (sd == NULL) return ASL_STATUS_FAILED;
 
 
                if (sd == NULL) return ASL_STATUS_FAILED;
 
@@ -150,7 +150,6 @@ asl_store_open_write(const char *basedir, asl_store_t **s)
        else
        {
                sd = fopen(path, "r+");
        else
        {
                sd = fopen(path, "r+");
-               free(path);
 
                if (sd == NULL) return ASL_STATUS_FAILED;
                if (fread(&last_id, sizeof(uint64_t), 1, sd) != 1)
 
                if (sd == NULL) return ASL_STATUS_FAILED;
                if (fread(&last_id, sizeof(uint64_t), 1, sd) != 1)
@@ -370,7 +369,7 @@ asl_store_sweep_file_cache(asl_store_t *s)
 static char *
 asl_store_make_ug_path(const char *dir, const char *base, const char *ext, uid_t ruid, gid_t rgid, uid_t *u, gid_t *g, mode_t *m)
 {
 static char *
 asl_store_make_ug_path(const char *dir, const char *base, const char *ext, uid_t ruid, gid_t rgid, uid_t *u, gid_t *g, mode_t *m)
 {
-       char *path  = NULL;
+       char *path = NULL;
 
        *u = 0;
        *g = 0;
 
        *u = 0;
        *g = 0;
@@ -516,7 +515,8 @@ asl_store_save(asl_store_t *s, asl_msg_t *msg)
 {
        struct tm ctm;
        time_t msg_time, now, bb;
 {
        struct tm ctm;
        time_t msg_time, now, bb;
-       char *path, *tmp_path, *tstring, *scratch;
+       char *path;
+       char tstring[128], tmp_path[MAXPATHLEN];
        const char *val;
        uid_t ruid;
        gid_t rgid;
        const char *val;
        uid_t ruid;
        gid_t rgid;
@@ -600,7 +600,6 @@ asl_store_save(asl_store_t *s, asl_msg_t *msg)
 
        if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;
 
 
        if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;
 
-       tstring = NULL;
        if (bb == 1)
        {
                /*
        if (bb == 1)
        {
                /*
@@ -619,19 +618,14 @@ asl_store_save(asl_store_t *s, asl_msg_t *msg)
                bb = mktime(&ctm);
 
                if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;
                bb = mktime(&ctm);
 
                if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;
-               asprintf(&tstring, "BB.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
+               snprintf(tstring, sizeof(tstring), "BB.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
        }
        else
        {
        }
        else
        {
-               asprintf(&tstring, "%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
+               snprintf(tstring, sizeof(tstring), "%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
        }
 
        }
 
-       if (tstring == NULL) return ASL_STATUS_NO_MEMORY;
-
        status = asl_store_file_open_write(s, tstring, ruid, rgid, bb, &f, now, check_cache);
        status = asl_store_file_open_write(s, tstring, ruid, rgid, bb, &f, now, check_cache);
-       free(tstring);
-       tstring = NULL;
-
        if (status != ASL_STATUS_OK) return status;
 
        status = asl_file_save(f, msg, &xid);
        if (status != ASL_STATUS_OK) return status;
 
        status = asl_file_save(f, msg, &xid);
@@ -652,36 +646,22 @@ asl_store_save(asl_store_t *s, asl_msg_t *msg)
 
                if (path != NULL)
                {
 
                if (path != NULL)
                {
-                       tmp_path = NULL;
-
                        len = strlen(path);
                        if ((len >= 4) && (!strcmp(path + len - 4, ".asl")))
                        {
                                /* rename xxxxxxx.asl to xxxxxxx.timestamp.asl */
                        len = strlen(path);
                        if ((len >= 4) && (!strcmp(path + len - 4, ".asl")))
                        {
                                /* rename xxxxxxx.asl to xxxxxxx.timestamp.asl */
-                               scratch = strdup(path);
-                               if (scratch != NULL)
-                               {
-                                       scratch[len - 4] = '\0';
-                                       asprintf(&tmp_path, "%s.%llu.asl", scratch, ftime);
-                                       free(scratch);
-
-                               }
+                               char scratch[MAXPATHLEN];
+                               snprintf(scratch, sizeof(scratch), "%s", path);
+                               scratch[len - 4] = '\0';
+                               snprintf(tmp_path, sizeof(tmp_path), "%s.%llu.asl", scratch, ftime);
                        }
                        else
                        {
                                /* append timestamp */
                        }
                        else
                        {
                                /* append timestamp */
-                               asprintf(&tmp_path, "%s.%llu", path, ftime);
+                               snprintf(tmp_path, sizeof(tmp_path), "%s.%llu", path, ftime);
                        }
 
                        }
 
-                       if (tmp_path == NULL)
-                       {
-                               status = ASL_STATUS_NO_MEMORY;
-                       }
-                       else
-                       {
-                               if (rename(path, tmp_path) != 0) status = ASL_STATUS_FAILED;
-                               free(tmp_path);
-                       }
+                       if (rename(path, tmp_path) != 0) status = ASL_STATUS_FAILED;
 
                        free(path);
                }
 
                        free(path);
                }
@@ -695,12 +675,11 @@ asl_store_save(asl_store_t *s, asl_msg_t *msg)
 static ASL_STATUS
 asl_store_mkdir(asl_store_t *s, const char *dir, mode_t m)
 {
 static ASL_STATUS
 asl_store_mkdir(asl_store_t *s, const char *dir, mode_t m)
 {
-       char *tstring = NULL;
+       char tstring[MAXPATHLEN];
        int status;
        struct stat sb;
 
        int status;
        struct stat sb;
 
-       asprintf(&tstring, "%s/%s", s->base_dir, dir);
-       if (tstring == NULL) return ASL_STATUS_NO_MEMORY;
+       snprintf(tstring, sizeof(tstring), "%s/%s", s->base_dir, dir);
 
        memset(&sb, 0, sizeof(struct stat));
        status = stat(tstring, &sb);
 
        memset(&sb, 0, sizeof(struct stat));
        status = stat(tstring, &sb);
@@ -708,32 +687,22 @@ asl_store_mkdir(asl_store_t *s, const char *dir, mode_t m)
        if (status == 0)
        {
                /* must be a directory */
        if (status == 0)
        {
                /* must be a directory */
-               if (!S_ISDIR(sb.st_mode))
-               {
-                       free(tstring);
-                       return ASL_STATUS_INVALID_STORE;
-               }
+               if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE;
        }
        else
        {
                if (errno == ENOENT)
                {
                        /* doesn't exist - create it */
        }
        else
        {
                if (errno == ENOENT)
                {
                        /* doesn't exist - create it */
-                       if (mkdir(tstring, m) != 0)
-                       {
-                               free(tstring);
-                               return ASL_STATUS_WRITE_FAILED;
-                       }
+                       if (mkdir(tstring, m) != 0) return ASL_STATUS_WRITE_FAILED;
                }
                else
                {
                        /* stat failed for some other reason */
                }
                else
                {
                        /* stat failed for some other reason */
-                       free(tstring);
                        return ASL_STATUS_FAILED;
                }
        }
 
                        return ASL_STATUS_FAILED;
                }
        }
 
-       free(tstring);
        return ASL_STATUS_OK;
 }
 
        return ASL_STATUS_OK;
 }
 
@@ -742,7 +711,8 @@ asl_store_open_aux(asl_store_t *s, asl_msg_t *msg, int *out_fd, char **url)
 {
        struct tm ctm;
        time_t msg_time, bb;
 {
        struct tm ctm;
        time_t msg_time, bb;
-       char *path, *dir, *tstring;
+       char *path;
+       char tstring[128], dir[128];
        const char *val;
        uid_t ruid, u;
        gid_t rgid, g;
        const char *val;
        uid_t ruid, u;
        gid_t rgid, g;
@@ -782,7 +752,6 @@ asl_store_open_aux(asl_store_t *s, asl_msg_t *msg, int *out_fd, char **url)
 
        if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;
 
 
        if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;
 
-       dir = NULL;
        if (bb == 1)
        {
                /*
        if (bb == 1)
        {
                /*
@@ -801,35 +770,25 @@ asl_store_open_aux(asl_store_t *s, asl_msg_t *msg, int *out_fd, char **url)
                bb = mktime(&ctm);
 
                if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;
                bb = mktime(&ctm);
 
                if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;
-               asprintf(&dir, "BB.AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
+               snprintf(dir, sizeof(dir), "BB.AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
        }
        else
        {
        }
        else
        {
-               asprintf(&dir, "AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
+               snprintf(dir, sizeof(dir), "AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
        }
 
        }
 
-       if (dir == NULL) return ASL_STATUS_NO_MEMORY;
-
        status = asl_store_mkdir(s, dir, 0755);
        status = asl_store_mkdir(s, dir, 0755);
-       if (status != ASL_STATUS_OK)
-       {
-               free(dir);
-               return status;
-       }
+       if (status != ASL_STATUS_OK) return status;
 
        fid = s->next_id;
        s->next_id++;
 
        fid = s->next_id;
        s->next_id++;
-       tstring = NULL;
 
 
-       asprintf(&tstring, "%s/%llu", dir, fid);
-       free(dir);
-       if (tstring == NULL) return ASL_STATUS_NO_MEMORY;
+       snprintf(tstring, sizeof(tstring), "%s/%llu", dir, fid);
 
        u = 0;
        g = 0;
        m = 0644;
        path = asl_store_make_ug_path(s->base_dir, tstring, NULL, ruid, rgid, &u, &g, &m);
 
        u = 0;
        g = 0;
        m = 0644;
        path = asl_store_make_ug_path(s->base_dir, tstring, NULL, ruid, rgid, &u, &g, &m);
-       free(tstring);
        if (path == NULL) return ASL_STATUS_NO_MEMORY;
 
        fd = asl_file_create(path, u, g, m);
        if (path == NULL) return ASL_STATUS_NO_MEMORY;
 
        fd = asl_file_create(path, u, g, m);
@@ -857,7 +816,7 @@ asl_store_match(asl_store_t *s, asl_msg_list_t *qlist, uint64_t *last_id, uint64
        struct dirent *dent;
        uint32_t status;
        asl_file_t *f;
        struct dirent *dent;
        uint32_t status;
        asl_file_t *f;
-       char *path;
+       char path[MAXPATHLEN];
        asl_file_list_t *files;
        asl_msg_list_t *res;
 
        asl_file_list_t *files;
        asl_msg_list_t *res;
 
@@ -875,12 +834,10 @@ asl_store_match(asl_store_t *s, asl_msg_list_t *qlist, uint64_t *last_id, uint64
        {
                if (dent->d_name[0] == '.') continue;
 
        {
                if (dent->d_name[0] == '.') continue;
 
-               path = NULL;
-               asprintf(&path, "%s/%s", s->base_dir, dent->d_name);
+               snprintf(path, sizeof(path), "%s/%s", s->base_dir, dent->d_name);
 
                /* NB asl_file_open_read will fail if path is NULL, if the file is not an ASL store file, or if it isn't readable */
                status = asl_file_open_read(path, &f);
 
                /* NB asl_file_open_read will fail if path is NULL, if the file is not an ASL store file, or if it isn't readable */
                status = asl_file_open_read(path, &f);
-               if (path != NULL) free(path);
                if ((status != ASL_STATUS_OK) || (f == NULL)) continue;
 
                files = asl_file_list_add(files, f);
                if ((status != ASL_STATUS_OK) || (f == NULL)) continue;
 
                files = asl_file_list_add(files, f);
@@ -986,7 +943,7 @@ asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction)
        struct dirent *dent;
        uint32_t status;
        asl_file_t *f;
        struct dirent *dent;
        uint32_t status;
        asl_file_t *f;
-       char *path;
+       char path[MAXPATHLEN];
        asl_file_list_t *files;
 
        if (s == NULL) return ASL_STATUS_INVALID_STORE;
        asl_file_list_t *files;
 
        if (s == NULL) return ASL_STATUS_INVALID_STORE;
@@ -1006,8 +963,7 @@ asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction)
        {
                if (dent->d_name[0] == '.') continue;
 
        {
                if (dent->d_name[0] == '.') continue;
 
-               path = NULL;
-               asprintf(&path, "%s/%s", s->base_dir, dent->d_name);
+               snprintf(path, sizeof(path), "%s/%s", s->base_dir, dent->d_name);
 
                /*
                 * NB asl_file_open_read will fail if path is NULL,
 
                /*
                 * NB asl_file_open_read will fail if path is NULL,
@@ -1015,7 +971,6 @@ asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction)
                 * We expect that.
                 */
                status = asl_file_open_read(path, &f);
                 * We expect that.
                 */
                status = asl_file_open_read(path, &f);
-               if (path != NULL) free(path);
                if ((status != ASL_STATUS_OK) || (f == NULL)) continue;
 
                files = asl_file_list_add(files, f);
                if ((status != ASL_STATUS_OK) || (f == NULL)) continue;
 
                files = asl_file_list_add(files, f);
@@ -1141,7 +1096,6 @@ _jump_search(asl_object_private_t *obj, asl_object_private_t *query)
        asl_msg_list_t *out = NULL;
        asl_msg_list_t *ql = NULL;
        uint64_t last;
        asl_msg_list_t *out = NULL;
        asl_msg_list_t *ql = NULL;
        uint64_t last;
-       uint32_t status = ASL_STATUS_FAILED;
 
        if (query == NULL)
        {
 
        if (query == NULL)
        {
@@ -1160,7 +1114,6 @@ _jump_search(asl_object_private_t *obj, asl_object_private_t *query)
                asl_msg_list_release(ql);
        }
 
                asl_msg_list_release(ql);
        }
 
-       if (status != ASL_STATUS_OK) return NULL;
        return (asl_object_private_t *)out;
 }
 
        return (asl_object_private_t *)out;
 }
 
index 9ab5221cc394271bc5a06ebb2435b543db580667..ecb04d3ae9a35987025fe754c1290d27273d6877 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2007-2013 Apple Inc.  All rights reserved.
+ * Copyright (c) 2007-2015 Apple Inc.  All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -38,6 +38,9 @@
 #define ASL_STRING_QUANTUM 256
 static const char *cvis_7_13 = "abtnvfr";
 
 #define ASL_STRING_QUANTUM 256
 static const char *cvis_7_13 = "abtnvfr";
 
+/* Forward */
+asl_string_t *asl_string_append_no_encoding_len(asl_string_t *str, const char *app, size_t copylen);
+
 asl_string_t *
 asl_string_new(uint32_t encoding)
 {
 asl_string_t *
 asl_string_new(uint32_t encoding)
 {
@@ -53,7 +56,7 @@ asl_string_new(uint32_t encoding)
        str->bufsize = 0;
        str->cursor = 0;
 
        str->bufsize = 0;
        str->cursor = 0;
 
-       if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding(str, "         0 ");
+       if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding_len(str, "         0 ", 11);
        return str;
 }
 
        return str;
 }
 
@@ -90,6 +93,13 @@ asl_string_release_return_bytes(asl_string_t *str)
        char *out;
        if (str == NULL) return NULL;
 
        char *out;
        if (str == NULL) return NULL;
 
+       if (str->encoding & ASL_STRING_LEN)
+       {
+               char tmp[11];
+               snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
+               memcpy(str->buf, tmp, 10);
+       }
+
        if (OSAtomicDecrement32Barrier(&(str->refcount)) != 0)
        {
                /* string is still retained - copy buf */
        if (OSAtomicDecrement32Barrier(&(str->refcount)) != 0)
        {
                /* string is still retained - copy buf */
@@ -98,7 +108,7 @@ asl_string_release_return_bytes(asl_string_t *str)
                        if (str->bufsize == 0) return NULL;
 
                        vm_address_t new = 0;
                        if (str->bufsize == 0) return NULL;
 
                        vm_address_t new = 0;
-                       kern_return_t kstatus = vm_allocate(mach_task_self(), &new, str->bufsize, TRUE);
+                       kern_return_t kstatus = vm_allocate(mach_task_self(), &new, str->bufsize, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
                        if (kstatus != KERN_SUCCESS) return NULL;
 
                        memcpy((void *)new, str->buf, str->bufsize);
                        if (kstatus != KERN_SUCCESS) return NULL;
 
                        memcpy((void *)new, str->buf, str->bufsize);
@@ -120,6 +130,14 @@ char *
 asl_string_bytes(asl_string_t *str)
 {
        if (str == NULL) return NULL;
 asl_string_bytes(asl_string_t *str)
 {
        if (str == NULL) return NULL;
+
+       if (str->encoding & ASL_STRING_LEN)
+       {
+               char tmp[11];
+               snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
+               memcpy(str->buf, tmp, 10);
+       }
+
        return str->buf;
 }
 
        return str->buf;
 }
 
@@ -166,7 +184,7 @@ _asl_string_grow(asl_string_t *str, size_t len)
                kern_return_t kstatus;
                vm_address_t new = 0;
 
                kern_return_t kstatus;
                vm_address_t new = 0;
 
-               kstatus = vm_allocate(mach_task_self(), &new, newlen, TRUE);
+               kstatus = vm_allocate(mach_task_self(), &new, newlen, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
                if (kstatus != KERN_SUCCESS)
                {
                        new = 0;
                if (kstatus != KERN_SUCCESS)
                {
                        new = 0;
@@ -208,32 +226,26 @@ asl_string_append_char_no_encoding(asl_string_t *str, const char c)
 
        len = 1;
        if (str->bufsize == 0) len++;
 
        len = 1;
        if (str->bufsize == 0) len++;
-
        if (_asl_string_grow(str, len) < 0) return str;
 
        str->buf[str->cursor] = c;
        str->cursor++;
        str->buf[str->cursor] = '\0';
 
        if (_asl_string_grow(str, len) < 0) return str;
 
        str->buf[str->cursor] = c;
        str->cursor++;
        str->buf[str->cursor] = '\0';
 
-       if (str->encoding & ASL_STRING_LEN)
-       {
-               char tmp[11];
-               snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
-               memcpy(str->buf, tmp, 10);
-       }
-
        return str;
 }
 
 asl_string_t *
        return str;
 }
 
 asl_string_t *
-asl_string_append_no_encoding(asl_string_t *str, const char *app)
+asl_string_append_no_encoding_len(asl_string_t *str, const char *app, size_t copylen)
 {
        size_t len, applen;
 
        if (str == NULL) return NULL;
        if (app == NULL) return str;
 
 {
        size_t len, applen;
 
        if (str == NULL) return NULL;
        if (app == NULL) return str;
 
-       applen = strlen(app);
+       applen = copylen;
+       if (applen == 0) applen = strlen(app);
+
        len = applen;
        if (str->bufsize == 0) len++;
 
        len = applen;
        if (str->bufsize == 0) len++;
 
@@ -244,21 +256,21 @@ asl_string_append_no_encoding(asl_string_t *str, const char *app)
        str->cursor += applen;
        str->buf[str->cursor] = '\0';
 
        str->cursor += applen;
        str->buf[str->cursor] = '\0';
 
-       if (str->encoding & ASL_STRING_LEN)
-       {
-               char tmp[11];
-               snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
-               memcpy(str->buf, tmp, 10);
-       }
-
        return str;
 }
 
        return str;
 }
 
+asl_string_t *
+asl_string_append_no_encoding(asl_string_t *str, const char *app)
+{
+       return asl_string_append_no_encoding_len(str, app, 0);
+}
+
 static asl_string_t *
 asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
 {
 static asl_string_t *
 asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
 {
-       uint8_t x;
-       const char *p;
+       uint8_t x, y, z;
+       const uint8_t *s, *p;
+       size_t copylen;
 
        if (str == NULL) return NULL;
        if (app == NULL) return str;
 
        if (str == NULL) return NULL;
        if (app == NULL) return str;
@@ -267,33 +279,91 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
        {
                case ASL_ENCODE_NONE:
                {
        {
                case ASL_ENCODE_NONE:
                {
-                       return asl_string_append_no_encoding(str, app);
+                       return asl_string_append_no_encoding_len(str, app, 0);
                }
                case ASL_ENCODE_SAFE:
                {
                        /* minor encoding to reduce the likelyhood of spoof attacks */
                        const char *p;
 
                }
                case ASL_ENCODE_SAFE:
                {
                        /* minor encoding to reduce the likelyhood of spoof attacks */
                        const char *p;
 
+                       s = NULL;
+                       copylen = 0;
+
                        for (p = app; *p != '\0'; p++)
                        {
                        for (p = app; *p != '\0'; p++)
                        {
-                               if ((*p == 10) || (*p == 13))
+                               x = p[0];
+                               y = 0;
+                               z = 0;
+                               
+                               if (x != 0) y = p[1];
+                               if (y != 0) z = p[2];
+                               
+                               if ((x == 10) || (x == 13))
                                {
                                {
-                                       asl_string_append_no_encoding(str, "\n\t");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       asl_string_append_no_encoding_len(str, "\n\t", 2);
                                }
                                }
-                               else if (*p == 8)
+                               else if (x == 8)
                                {
                                {
-                                       asl_string_append_no_encoding(str, "^H");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       asl_string_append_no_encoding_len(str, "^H", 2);
+                               }
+                               else if ((x == 0xc2) && (y == 0x85))
+                               {
+                                       p++;
+                                       
+                                       /* next line - format like newline */
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+                                       
+                                       asl_string_append_no_encoding_len(str, "\n\t", 2);
+                               }
+                               else if ((x == 0xe2) && (y == 0x80) && ((z == 0xa8) || (z == 0xa9)))
+                               {
+                                       p += 3;
+                                       
+                                       /* line separator or paragraph separator - format like newline */
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+                                       
+                                       asl_string_append_no_encoding_len(str, "\n\t", 2);
                                }
                                else
                                {
                                }
                                else
                                {
-                                       asl_string_append_char_no_encoding(str, *p);
+                                       if (s == NULL) s = p;
+                                       copylen++;
                                }
                        }
 
                                }
                        }
 
+                       if (copylen > 0) asl_string_append_no_encoding_len(str, s, copylen);
+
                        return str;
                }
                case ASL_ENCODE_ASL:
                {
                        return str;
                }
                case ASL_ENCODE_ASL:
                {
+                       s = NULL;
+                       copylen = 0;
+
                        for (p = app; *p != '\0'; p++)
                        {
                                int meta = 0;
                        for (p = app; *p != '\0'; p++)
                        {
                                int meta = 0;
@@ -306,11 +376,25 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
                                        /* except meta-space, which is \240 */
                                        if (x == 160)
                                        {
                                        /* except meta-space, which is \240 */
                                        if (x == 160)
                                        {
-                                               asl_string_append_no_encoding(str, "\\240");
+                                               if (copylen > 0)
+                                               {
+                                                       asl_string_append_no_encoding_len(str, s, copylen);
+                                                       s = NULL;
+                                                       copylen = 0;
+                                               }
+
+                                               asl_string_append_no_encoding_len(str, "\\240", 4);
                                                continue;
                                        }
 
                                                continue;
                                        }
 
-                                       asl_string_append_no_encoding(str, "\\M");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       asl_string_append_no_encoding_len(str, "\\M", 2);
                                        x &= 0x7f;
                                        meta = 1;
                                }
                                        x &= 0x7f;
                                        meta = 1;
                                }
@@ -320,26 +404,48 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
                                {
                                        if (encode_space == 0)
                                        {
                                {
                                        if (encode_space == 0)
                                        {
-                                               asl_string_append_char_no_encoding(str, ' ');
+                                               if (s == NULL) s = p;
+                                               copylen++;
                                                continue;
                                        }
 
                                                continue;
                                        }
 
-                                       asl_string_append_no_encoding(str, "\\s");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       asl_string_append_no_encoding_len(str, "\\s", 2);
                                        continue;
                                }
 
                                /* \ is escaped */
                                if ((meta == 0) && (x == 92))
                                {
                                        continue;
                                }
 
                                /* \ is escaped */
                                if ((meta == 0) && (x == 92))
                                {
-                                       asl_string_append_no_encoding(str, "\\\\");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       asl_string_append_no_encoding_len(str, "\\\\", 2);
                                        continue;
                                }
 
                                /* [ and ] are escaped in ASL encoding */
                                if ((str->encoding & ASL_ENCODE_ASL) && (meta == 0) && ((*p == 91) || (*p == 93)))
                                {
                                        continue;
                                }
 
                                /* [ and ] are escaped in ASL encoding */
                                if ((str->encoding & ASL_ENCODE_ASL) && (meta == 0) && ((*p == 91) || (*p == 93)))
                                {
-                                       if (*p == '[') asl_string_append_no_encoding(str, "\\[");
-                                       else asl_string_append_no_encoding(str, "\\]");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       if (*p == '[') asl_string_append_no_encoding_len(str, "\\[", 2);
+                                       else asl_string_append_no_encoding_len(str, "\\]", 2);
                                        continue;
                                }
 
                                        continue;
                                }
 
@@ -348,10 +454,24 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
                                {
                                        if (meta == 0)
                                        {
                                {
                                        if (meta == 0)
                                        {
+                                               if (copylen > 0)
+                                               {
+                                                       asl_string_append_no_encoding_len(str, s, copylen);
+                                                       s = NULL;
+                                                       copylen = 0;
+                                               }
+
                                                asl_string_append_char_no_encoding(str, '\\');
                                        }
 
                                                asl_string_append_char_no_encoding(str, '\\');
                                        }
 
-                                       asl_string_append_no_encoding(str, "^?");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       asl_string_append_no_encoding_len(str, "^?", 2);
                                        continue;
                                }
 
                                        continue;
                                }
 
@@ -360,16 +480,34 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
                                {
                                        if (meta == 1)
                                        {
                                {
                                        if (meta == 1)
                                        {
+                                               if (copylen > 0)
+                                               {
+                                                       asl_string_append_no_encoding_len(str, s, copylen);
+                                                       s = NULL;
+                                                       copylen = 0;
+                                               }
+
                                                asl_string_append_char_no_encoding(str, '-');
                                                asl_string_append_char_no_encoding(str, '-');
+                                               asl_string_append_char_no_encoding(str, x);
+                                               continue;
                                        }
 
                                        }
 
-                                       asl_string_append_char_no_encoding(str, x);
+                                       if (s == NULL) s = p;
+                                       copylen++;
+
                                        continue;
                                }
 
                                /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
                                if ((meta == 0) && (x >= 7) && (x <= 13))
                                {
                                        continue;
                                }
 
                                /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
                                if ((meta == 0) && (x >= 7) && (x <= 13))
                                {
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
                                        asl_string_append_char_no_encoding(str, '\\');
                                        asl_string_append_char_no_encoding(str, cvis_7_13[x - 7]);
                                        continue;
                                        asl_string_append_char_no_encoding(str, '\\');
                                        asl_string_append_char_no_encoding(str, cvis_7_13[x - 7]);
                                        continue;
@@ -380,56 +518,133 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
                                {
                                        if (meta == 0)
                                        {
                                {
                                        if (meta == 0)
                                        {
+                                               if (copylen > 0)
+                                               {
+                                                       asl_string_append_no_encoding_len(str, s, copylen);
+                                                       s = NULL;
+                                                       copylen = 0;
+                                               }
+
                                                asl_string_append_char_no_encoding(str, '\\');
                                        }
 
                                                asl_string_append_char_no_encoding(str, '\\');
                                        }
 
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
                                        asl_string_append_char_no_encoding(str, '^');
                                        asl_string_append_char_no_encoding(str, 64 + x);
                                        continue;
                                }
 
                                        asl_string_append_char_no_encoding(str, '^');
                                        asl_string_append_char_no_encoding(str, 64 + x);
                                        continue;
                                }
 
-                               asl_string_append_char_no_encoding(str, x);
+                               if (s == NULL) s = p;
+                               copylen++;
+                       }
+
+                       if (copylen > 0)
+                       {
+                               asl_string_append_no_encoding_len(str, s, copylen);
+                               s = NULL;
+                               copylen = 0;
                        }
 
                        return str;
                }
                case ASL_ENCODE_XML:
                {
                        }
 
                        return str;
                }
                case ASL_ENCODE_XML:
                {
+                       s = NULL;
+                       copylen = 0;
+
                        for (p = app; *p != '\0'; p++)
                        {
                                x = *p;
 
                                if (x == '&')
                                {
                        for (p = app; *p != '\0'; p++)
                        {
                                x = *p;
 
                                if (x == '&')
                                {
-                                       asl_string_append_no_encoding(str, "&amp;");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       asl_string_append_no_encoding_len(str, "&amp;", 5);
                                }
                                else if (x == '<')
                                {
                                }
                                else if (x == '<')
                                {
-                                       asl_string_append_no_encoding(str, "&lt;");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       asl_string_append_no_encoding_len(str, "&lt;", 4);
                                }
                                else if (x == '>')
                                {
                                }
                                else if (x == '>')
                                {
-                                       asl_string_append_no_encoding(str, "&gt;");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       asl_string_append_no_encoding_len(str, "&gt;", 4);
                                }
                                else if (x == '"')
                                {
                                }
                                else if (x == '"')
                                {
-                                       asl_string_append_no_encoding(str, "&quot;");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       asl_string_append_no_encoding_len(str, "&quot;", 6);
                                }
                                else if (x == '\'')
                                {
                                }
                                else if (x == '\'')
                                {
-                                       asl_string_append_no_encoding(str, "&apos;");
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
+                                       asl_string_append_no_encoding_len(str, "&apos;", 6);
                                }
                                else if (iscntrl(x))
                                {
                                }
                                else if (iscntrl(x))
                                {
+                                       if (copylen > 0)
+                                       {
+                                               asl_string_append_no_encoding_len(str, s, copylen);
+                                               s = NULL;
+                                               copylen = 0;
+                                       }
+
                                        char tmp[8];
                                        snprintf(tmp, sizeof(tmp), "&#x%02hhx;", x);
                                        char tmp[8];
                                        snprintf(tmp, sizeof(tmp), "&#x%02hhx;", x);
-                                       asl_string_append_no_encoding(str, tmp);
+                                       asl_string_append_no_encoding_len(str, tmp, 6);
                                }
                                else
                                {
                                }
                                else
                                {
-                                       asl_string_append_char_no_encoding(str, x);
+                                       if (s == NULL) s = p;
+                                       copylen++;
                                }
                        }
                                }
                        }
+
+                       if (copylen > 0)
+                       {
+                               asl_string_append_no_encoding_len(str, s, copylen);
+                               s = NULL;
+                               copylen = 0;
+                       }
+
+                       return str;
                }
                default:
                {
                }
                default:
                {
@@ -514,19 +729,19 @@ asl_string_append_op(asl_string_t *str, uint32_t op)
        }
 
        opstr[i] = '\0';
        }
 
        opstr[i] = '\0';
-       return asl_string_append_no_encoding(str, opstr);
+       return asl_string_append_no_encoding_len(str, opstr, 0);
 }
 
 asl_string_t *
 asl_string_append_xml_tag(asl_string_t *str, const char *tag, const char *s)
 {
 }
 
 asl_string_t *
 asl_string_append_xml_tag(asl_string_t *str, const char *tag, const char *s)
 {
-       asl_string_append_no_encoding(str, "\t\t<");
-       asl_string_append_no_encoding(str, tag);
-       asl_string_append_no_encoding(str, ">");
+       asl_string_append_no_encoding_len(str, "\t\t<", 3);
+       asl_string_append_no_encoding_len(str, tag, 0);
+       asl_string_append_char_no_encoding(str, '>');
        asl_string_append_internal(str, s, 0);
        asl_string_append_internal(str, s, 0);
-       asl_string_append_no_encoding(str, "</");
-       asl_string_append_no_encoding(str, tag);
-       asl_string_append_no_encoding(str, ">\n");
+       asl_string_append_no_encoding_len(str, "</", 2);
+       asl_string_append_no_encoding_len(str, tag, 0);
+       asl_string_append_no_encoding_len(str, ">\n", 2);
        return str;
 }
 
        return str;
 }
 
index 2965f9721afbc24c55974f97aa3061eaa66f1654..45f940909cbdf924fc549020a2d433373fefcfd5 100644 (file)
@@ -35,6 +35,7 @@
 #include <os/assumes.h>
 #include <xpc/xpc.h>
 #include <syslog.h>
 #include <os/assumes.h>
 #include <xpc/xpc.h>
 #include <syslog.h>
+#include <asl_core.h>
 #include <asl_private.h>
 
 static uint8_t *b64charset = (uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 #include <asl_private.h>
 
 static uint8_t *b64charset = (uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
index 91fb2131ba318e760c01a0d712558b193a9ba309..1975d4d2b699756086cbe4d05e87e3e810a66288 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 1999-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2015 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -65,6 +65,8 @@
 #include <asl.h>
 #include <asl_msg.h>
 #include <asl_private.h>
 #include <asl.h>
 #include <asl_msg.h>
 #include <asl_private.h>
+#include <os/trace.h>
+#include <os/log_private.h>
 
 #ifdef __STDC__
 #include <stdarg.h>
 
 #ifdef __STDC__
 #include <stdarg.h>
@@ -77,79 +79,150 @@ extern const char *asl_syslog_faciliy_num_to_name(int n);
 
 #ifdef BUILDING_VARIANT
 __private_extern__ pthread_mutex_t _sl_lock;
 
 #ifdef BUILDING_VARIANT
 __private_extern__ pthread_mutex_t _sl_lock;
-__private_extern__ aslclient _sl_asl;
+__private_extern__ asl_object_t _sl_asl;
 __private_extern__ char *_sl_ident;
 __private_extern__ int _sl_fac;
 __private_extern__ int _sl_opts;
 __private_extern__ int _sl_mask;
 #else /* !BUILDING_VARIANT */
 __private_extern__ pthread_mutex_t _sl_lock = PTHREAD_MUTEX_INITIALIZER;
 __private_extern__ char *_sl_ident;
 __private_extern__ int _sl_fac;
 __private_extern__ int _sl_opts;
 __private_extern__ int _sl_mask;
 #else /* !BUILDING_VARIANT */
 __private_extern__ pthread_mutex_t _sl_lock = PTHREAD_MUTEX_INITIALIZER;
-__private_extern__ aslclient _sl_asl = NULL;
+__private_extern__ asl_object_t _sl_asl = NULL;
 __private_extern__ char *_sl_ident = NULL;
 __private_extern__ int _sl_fac = 0;
 __private_extern__ int _sl_opts = 0;
 __private_extern__ int _sl_mask = 0;
 #endif /* BUILDING_VARIANT */
 
 __private_extern__ char *_sl_ident = NULL;
 __private_extern__ int _sl_fac = 0;
 __private_extern__ int _sl_opts = 0;
 __private_extern__ int _sl_mask = 0;
 #endif /* BUILDING_VARIANT */
 
+#define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE)
+
+static const uint8_t shim_syslog_to_trace_type[8] = {
+       OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, // LOG_EMERG, LOG_ALERT, LOG_CRIT
+       OS_TRACE_TYPE_ERROR, // LOG_ERROR
+       OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, // LOG_WARN, LOG_NOTICE, LOG_INFO
+       OS_TRACE_TYPE_DEBUG // LOG_DEBUG
+};
+
+extern uint32_t _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel);
+extern uint32_t _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap);
+
+
+/* SHIM SPI */
+asl_object_t
+_syslog_asl_client()
+{
+       pthread_mutex_lock(&_sl_lock);
+       if (_sl_asl == NULL)
+       {
+               _sl_asl = asl_open(NULL, NULL, ASL_OPT_SYSLOG_LEGACY);
+               _sl_mask = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG);
+               asl_set_filter(_sl_asl, _sl_mask);
+       }
+       pthread_mutex_unlock(&_sl_lock);
+
+       return _sl_asl;
+}
+
 /*
  * syslog, vsyslog --
  *     print message on log file; output is intended for syslogd(8).
  */
 /*
  * syslog, vsyslog --
  *     print message on log file; output is intended for syslogd(8).
  */
+
+void
+vsyslog(int pri, const char *fmt, va_list ap)
+{
+       int level = pri & LOG_PRIMASK;
+       uint32_t eval;
+       _syslog_asl_client();
+
+       eval = _asl_evaluate_send(_sl_asl, NULL, level);
+       
+       if (eval & EVAL_SEND_TRACE)
+       {
+               va_list ap_copy;
+               uint8_t trace_type = shim_syslog_to_trace_type[level];
+
+               va_copy(ap_copy, ap);
+               os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, fmt, ap_copy, NULL);
+               va_end(ap_copy);
+       }
+       
+       if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
+       {
+               asl_object_t msg = asl_new(ASL_TYPE_MSG);
+               const char *facility;
+               int fac = pri & LOG_FACMASK;
+               
+               if (fac != 0)
+               {
+                       facility = asl_syslog_faciliy_num_to_name(fac);
+                       if (facility != NULL) asl_set(msg, ASL_KEY_FACILITY, facility);
+               }
+               
+               if (eval & EVAL_SEND_TRACE) asl_set(msg, "ASLSHIM", "2");
+               
+               _asl_lib_vlog(_sl_asl, eval, msg, fmt, ap);
+               
+               asl_release(msg);
+       }
+}
+
 void
 #ifdef __STDC__
 syslog(int pri, const char *fmt, ...)
 #else
 syslog(pri, fmt, va_alist)
 void
 #ifdef __STDC__
 syslog(int pri, const char *fmt, ...)
 #else
 syslog(pri, fmt, va_alist)
-       int pri;
-       char *fmt;
-       va_dcl
+int pri;
+char *fmt;
+va_dcl
 #endif
 {
 #endif
 {
-       va_list ap;
-
+       int level = pri & LOG_PRIMASK;
+       uint32_t eval;
+       _syslog_asl_client();
+
+       eval = _asl_evaluate_send(_sl_asl, NULL, level);
+       
+       if (eval & EVAL_SEND_TRACE)
+       {
+               va_list ap;
+               uint8_t trace_type = shim_syslog_to_trace_type[level];
+               
 #ifdef __STDC__
 #ifdef __STDC__
-       va_start(ap, fmt);
+               va_start(ap, fmt);
 #else
 #else
-       va_start(ap);
+               va_start(ap);
 #endif
 #endif
-       vsyslog(pri, fmt, ap);
-       va_end(ap);
-}
-
-void
-vsyslog(int pri, const char *fmt, va_list ap)
-{
-       int fac;
-       asl_msg_t *facmsg;
-       const char *facility;
-
-       facmsg = NULL;
-       fac = pri & LOG_FACMASK;
-       if (fac != 0)
+               os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, fmt, ap, NULL);
+               va_end(ap);
+       }
+       
+       if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
        {
        {
-               facility = asl_syslog_faciliy_num_to_name(fac);
-               if (facility != NULL)
+               va_list ap;
+               asl_object_t msg = asl_new(ASL_TYPE_MSG);
+               const char *facility;
+               int fac = pri & LOG_FACMASK;
+
+               if (fac != 0)
                {
                {
-                       facmsg = asl_msg_new(ASL_TYPE_MSG);
-                       asl_msg_set_key_val(facmsg, ASL_KEY_FACILITY, facility);
+                       facility = asl_syslog_faciliy_num_to_name(fac);
+                       if (facility != NULL) asl_set(msg, ASL_KEY_FACILITY, facility);
                }
                }
+       
+               if (eval & EVAL_SEND_TRACE) asl_set(msg, "ASLSHIM", "2");
+               
+#ifdef __STDC__
+               va_start(ap, fmt);
+#else
+               va_start(ap);
+#endif
+               _asl_lib_vlog(_sl_asl, eval, msg, fmt, ap);
+               va_end(ap);
+               
+               asl_release(msg);
        }
        }
-
-       pthread_mutex_lock(&_sl_lock);
-
-       /* open syslog ASL client if required */
-       if (_sl_asl == NULL)
-       {
-               _sl_asl = asl_open(NULL, NULL, ASL_OPT_SYSLOG_LEGACY);
-               _sl_mask = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG);
-               asl_set_filter(_sl_asl, _sl_mask);
-       }
-
-       asl_vlog(_sl_asl, (aslmsg)facmsg, LOG_PRI(pri), fmt, ap);
-
-       pthread_mutex_unlock(&_sl_lock);
-
-       if (facmsg != NULL) asl_msg_release(facmsg);
 }
 
 #ifndef BUILDING_VARIANT
 }
 
 #ifndef BUILDING_VARIANT
@@ -162,7 +235,7 @@ openlog(const char *ident, int opts, int logfac)
 
        pthread_mutex_lock(&_sl_lock);
 
 
        pthread_mutex_lock(&_sl_lock);
 
-       if (_sl_asl != NULL) asl_close(_sl_asl);
+       if (_sl_asl != NULL) asl_release(_sl_asl);
        _sl_asl = NULL;
 
        free(_sl_ident);
        _sl_asl = NULL;
 
        free(_sl_ident);
index 566416bfd0e384170975163d5cb48f7a46986141..31b71001dddc721ce47ab27bbe1a79b6326b85e5 100644 (file)
@@ -33,7 +33,6 @@
                        isa = PBXAggregateTarget;
                        buildConfigurationList = 3FFD4402174862D0007DAC1B /* Build configuration list for PBXAggregateTarget "executables_Sim" */;
                        buildPhases = (
                        isa = PBXAggregateTarget;
                        buildConfigurationList = 3FFD4402174862D0007DAC1B /* Build configuration list for PBXAggregateTarget "executables_Sim" */;
                        buildPhases = (
-                               3F5F5B9C17487ADB00C12281 /* Configuration */,
                        );
                        dependencies = (
                                3FFD440717486325007DAC1B /* PBXTargetDependency */,
                        );
                        dependencies = (
                                3FFD440717486325007DAC1B /* PBXTargetDependency */,
@@ -59,6 +58,7 @@
 
 /* Begin PBXBuildFile section */
                2D30656E150E6EFF00F31A54 /* asl_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D30656C150E6EFF00F31A54 /* asl_common.c */; };
 
 /* Begin PBXBuildFile section */
                2D30656E150E6EFF00F31A54 /* asl_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D30656C150E6EFF00F31A54 /* asl_common.c */; };
+               2D30D2811AE6C84200673818 /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D30D27F1AE6C84200673818 /* daemon.c */; };
                2D31F3C517E77F3300F2A60C /* asl_client.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C117E77F3300F2A60C /* asl_client.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2D31F3C617E77F3300F2A60C /* asl_msg_list.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C217E77F3300F2A60C /* asl_msg_list.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2D31F3C717E77F3300F2A60C /* asl_object.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C317E77F3300F2A60C /* asl_object.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2D31F3C517E77F3300F2A60C /* asl_client.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C117E77F3300F2A60C /* asl_client.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2D31F3C617E77F3300F2A60C /* asl_msg_list.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C217E77F3300F2A60C /* asl_msg_list.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2D31F3C717E77F3300F2A60C /* asl_object.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C317E77F3300F2A60C /* asl_object.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2D31F3D017E77F8800F2A60C /* asl_string.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D31F3CC17E77F8800F2A60C /* asl_string.c */; };
                2D60F61115657D0F00F2E3F9 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D60F61015657D0F00F2E3F9 /* libz.dylib */; };
                2D9DEB64150E6FE80059BA61 /* asl_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D30656D150E6EFF00F31A54 /* asl_common.h */; };
                2D31F3D017E77F8800F2A60C /* asl_string.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D31F3CC17E77F8800F2A60C /* asl_string.c */; };
                2D60F61115657D0F00F2E3F9 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D60F61015657D0F00F2E3F9 /* libz.dylib */; };
                2D9DEB64150E6FE80059BA61 /* asl_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D30656D150E6EFF00F31A54 /* asl_common.h */; };
+               2DAF75551AE8613000054190 /* com.apple.activity_tracing.CacheDelete.plist in Copy CacheDelete plist */ = {isa = PBXBuildFile; fileRef = 2DAF75541AE8610200054190 /* com.apple.activity_tracing.CacheDelete.plist */; };
                2DCF701A150E97C0002D5E8F /* libaslcommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 505ACB9D108FD16400197086 /* libaslcommon.a */; };
                2DCF701A150E97C0002D5E8F /* libaslcommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 505ACB9D108FD16400197086 /* libaslcommon.a */; };
+               2DEE8C411AE575A2007B5CBE /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DEE8C401AE575A2007B5CBE /* CoreFoundation.framework */; };
+               2DEE8C431AE575AB007B5CBE /* CacheDelete.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DEE8C421AE575AB007B5CBE /* CacheDelete.framework */; };
+               2DEE8C461AE5798B007B5CBE /* cache_delete.c in Sources */ = {isa = PBXBuildFile; fileRef = 2DEE8C441AE5798B007B5CBE /* cache_delete.c */; };
                3F6F43F21613A8E300CA9ADB /* asl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43CF1613A8E300CA9ADB /* asl.h */; settings = {ATTRIBUTES = (Public, ); }; };
                3F6F43F31613A8E300CA9ADB /* asl_core.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43D01613A8E300CA9ADB /* asl_core.h */; settings = {ATTRIBUTES = (Private, ); }; };
                3F6F43F41613A8E300CA9ADB /* asl_file.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43D11613A8E300CA9ADB /* asl_file.h */; settings = {ATTRIBUTES = (Private, ); }; };
                3F6F43F21613A8E300CA9ADB /* asl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43CF1613A8E300CA9ADB /* asl.h */; settings = {ATTRIBUTES = (Public, ); }; };
                3F6F43F31613A8E300CA9ADB /* asl_core.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43D01613A8E300CA9ADB /* asl_core.h */; settings = {ATTRIBUTES = (Private, ); }; };
                3F6F43F41613A8E300CA9ADB /* asl_file.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43D11613A8E300CA9ADB /* asl_file.h */; settings = {ATTRIBUTES = (Private, ); }; };
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
+               2D30D27D1AE6BBA000673818 /* Copy CacheDelete plist */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /System/Library/CacheDelete;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               2DAF75551AE8613000054190 /* com.apple.activity_tracing.CacheDelete.plist in Copy CacheDelete plist */,
+                       );
+                       name = "Copy CacheDelete plist";
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
                3F6F44131613AA9300CA9ADB /* Install man3 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                3F6F44131613AA9300CA9ADB /* Install man3 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man3";
+                       dstPath = /usr/share/man/man3;
                        dstSubfolderSpec = 0;
                        files = (
                                3F6F44141613AAA600CA9ADB /* asl.3 in Install man3 */,
                        dstSubfolderSpec = 0;
                        files = (
                                3F6F44141613AAA600CA9ADB /* asl.3 in Install man3 */,
                503A82631099037D00B0D08A /* Copy Manpage.8 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                503A82631099037D00B0D08A /* Copy Manpage.8 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man8";
+                       dstPath = /usr/share/man/man8;
                        dstSubfolderSpec = 0;
                        files = (
                                503A82741099045F00B0D08A /* aslmanager.8 in Copy Manpage.8 */,
                        dstSubfolderSpec = 0;
                        files = (
                                503A82741099045F00B0D08A /* aslmanager.8 in Copy Manpage.8 */,
                503A8285109904FD00B0D08A /* Copy Manpage.1 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                503A8285109904FD00B0D08A /* Copy Manpage.1 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man1";
+                       dstPath = /usr/share/man/man1;
                        dstSubfolderSpec = 0;
                        files = (
                                503A82761099049900B0D08A /* syslog.1 in Copy Manpage.1 */,
                        dstSubfolderSpec = 0;
                        files = (
                                503A82761099049900B0D08A /* syslog.1 in Copy Manpage.1 */,
                503A8286109904FD00B0D08A /* Copy Manpage.8 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                503A8286109904FD00B0D08A /* Copy Manpage.8 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man8";
+                       dstPath = /usr/share/man/man8;
                        dstSubfolderSpec = 0;
                        files = (
                                503A8278109904C000B0D08A /* syslogd.8 in Copy Manpage.8 */,
                        dstSubfolderSpec = 0;
                        files = (
                                503A8278109904C000B0D08A /* syslogd.8 in Copy Manpage.8 */,
                503A8287109904FD00B0D08A /* Copy Manpages.5 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                503A8287109904FD00B0D08A /* Copy Manpages.5 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man5";
+                       dstPath = /usr/share/man/man5;
                        dstSubfolderSpec = 0;
                        files = (
                                503A827A109904E400B0D08A /* asl.conf.5 in Copy Manpages.5 */,
                        dstSubfolderSpec = 0;
                        files = (
                                503A827A109904E400B0D08A /* asl.conf.5 in Copy Manpages.5 */,
 /* Begin PBXFileReference section */
                2D30656C150E6EFF00F31A54 /* asl_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_common.c; sourceTree = "<group>"; };
                2D30656D150E6EFF00F31A54 /* asl_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_common.h; sourceTree = "<group>"; };
 /* Begin PBXFileReference section */
                2D30656C150E6EFF00F31A54 /* asl_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_common.c; sourceTree = "<group>"; };
                2D30656D150E6EFF00F31A54 /* asl_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_common.h; sourceTree = "<group>"; };
+               2D30D27F1AE6C84200673818 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = daemon.c; path = aslmanager.tproj/daemon.c; sourceTree = "<group>"; };
+               2D30D2801AE6C84200673818 /* daemon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = daemon.h; path = aslmanager.tproj/daemon.h; sourceTree = "<group>"; };
                2D31F3C117E77F3300F2A60C /* asl_client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_client.h; sourceTree = "<group>"; };
                2D31F3C217E77F3300F2A60C /* asl_msg_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_msg_list.h; sourceTree = "<group>"; };
                2D31F3C317E77F3300F2A60C /* asl_object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_object.h; sourceTree = "<group>"; };
                2D31F3C117E77F3300F2A60C /* asl_client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_client.h; sourceTree = "<group>"; };
                2D31F3C217E77F3300F2A60C /* asl_msg_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_msg_list.h; sourceTree = "<group>"; };
                2D31F3C317E77F3300F2A60C /* asl_object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_object.h; sourceTree = "<group>"; };
                2D31F3CB17E77F8800F2A60C /* asl_object.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_object.c; sourceTree = "<group>"; };
                2D31F3CC17E77F8800F2A60C /* asl_string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_string.c; sourceTree = "<group>"; };
                2D60F61015657D0F00F2E3F9 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
                2D31F3CB17E77F8800F2A60C /* asl_object.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_object.c; sourceTree = "<group>"; };
                2D31F3CC17E77F8800F2A60C /* asl_string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_string.c; sourceTree = "<group>"; };
                2D60F61015657D0F00F2E3F9 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
+               2D9C4F131B3A29E700219FB3 /* com.apple.system.log */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = com.apple.system.log; path = syslogd.tproj/com.apple.system.log; sourceTree = "<group>"; };
+               2DAF75541AE8610200054190 /* com.apple.activity_tracing.CacheDelete.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.activity_tracing.CacheDelete.plist; path = aslmanager.tproj/com.apple.activity_tracing.CacheDelete.plist; sourceTree = "<group>"; };
                2DB4DA0A125FC69A001CDC45 /* after_install.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = after_install.sh; path = syslogd.tproj/after_install.sh; sourceTree = "<group>"; };
                2DB8178915589D0C004D0BDE /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = entitlements.plist; path = util.tproj/entitlements.plist; sourceTree = "<group>"; };
                2DB4DA0A125FC69A001CDC45 /* after_install.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = after_install.sh; path = syslogd.tproj/after_install.sh; sourceTree = "<group>"; };
                2DB8178915589D0C004D0BDE /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = entitlements.plist; path = util.tproj/entitlements.plist; sourceTree = "<group>"; };
+               2DEE8C401AE575A2007B5CBE /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = ../../../../../../../../System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<group>"; };
+               2DEE8C421AE575AB007B5CBE /* CacheDelete.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CacheDelete.framework; path = ../../../../../../../../System/Library/PrivateFrameworks/CacheDelete.framework; sourceTree = "<group>"; };
+               2DEE8C441AE5798B007B5CBE /* cache_delete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cache_delete.c; path = aslmanager.tproj/cache_delete.c; sourceTree = "<group>"; };
+               2DEE8C451AE5798B007B5CBE /* cache_delete.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cache_delete.h; path = aslmanager.tproj/cache_delete.h; sourceTree = "<group>"; };
                3F6B6311185AF66C00F692C5 /* aslmanager.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = aslmanager.xcconfig; sourceTree = "<group>"; };
                3F6B6312185AF66C00F692C5 /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = "<group>"; };
                3F6B6313185AF66C00F692C5 /* syslogd.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = syslogd.xcconfig; sourceTree = "<group>"; };
                3F6B6311185AF66C00F692C5 /* aslmanager.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = aslmanager.xcconfig; sourceTree = "<group>"; };
                3F6B6312185AF66C00F692C5 /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = "<group>"; };
                3F6B6313185AF66C00F692C5 /* syslogd.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = syslogd.xcconfig; sourceTree = "<group>"; };
                3F6F43E81613A8E300CA9ADB /* asl_store.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_store.c; sourceTree = "<group>"; };
                3F6F43E91613A8E300CA9ADB /* asl_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_util.c; sourceTree = "<group>"; };
                3F900DB619383950003CA7E6 /* sim-compat-symlink.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "sim-compat-symlink.sh"; sourceTree = "<group>"; };
                3F6F43E81613A8E300CA9ADB /* asl_store.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_store.c; sourceTree = "<group>"; };
                3F6F43E91613A8E300CA9ADB /* asl_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_util.c; sourceTree = "<group>"; };
                3F900DB619383950003CA7E6 /* sim-compat-symlink.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "sim-compat-symlink.sh"; sourceTree = "<group>"; };
-               3FCCB5361749B53D00F8FEBC /* asl_sim.conf */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl_sim.conf; path = syslogd.tproj/asl_sim.conf; sourceTree = "<group>"; };
+               3FCCB5361749B53D00F8FEBC /* asl.conf.ios_sim */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl.conf.ios_sim; path = syslogd.tproj/asl.conf.ios_sim; sourceTree = "<group>"; };
+               3FE6E8391A529FEF0075D75F /* asl.conf.ios */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl.conf.ios; path = syslogd.tproj/asl.conf.ios; sourceTree = "<group>"; };
+               3FE6E83A1A529FEF0075D75F /* asl.conf.osx */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl.conf.osx; path = syslogd.tproj/asl.conf.osx; sourceTree = "<group>"; };
+               3FE6E83B1A529FEF0075D75F /* syslog.conf */ = {isa = PBXFileReference; lastKnownFileType = text; name = syslog.conf; path = syslogd.tproj/syslog.conf; sourceTree = "<group>"; };
                3FE798E316161F2A00D547B0 /* syslog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = syslog.c; sourceTree = "<group>"; };
                3FE798E516161F3A00D547B0 /* syslog.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = syslog.3; sourceTree = "<group>"; };
                3FFD43F817485C5B007DAC1B /* libasl.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libasl.xcconfig; sourceTree = "<group>"; };
                3FE798E316161F2A00D547B0 /* syslog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = syslog.c; sourceTree = "<group>"; };
                3FE798E516161F3A00D547B0 /* syslog.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = syslog.3; sourceTree = "<group>"; };
                3FFD43F817485C5B007DAC1B /* libasl.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libasl.xcconfig; sourceTree = "<group>"; };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               2DEE8C431AE575AB007B5CBE /* CacheDelete.framework in Frameworks */,
+                               2DEE8C411AE575A2007B5CBE /* CoreFoundation.framework in Frameworks */,
                                2D60F61115657D0F00F2E3F9 /* libz.dylib in Frameworks */,
                                2DCF701A150E97C0002D5E8F /* libaslcommon.a in Frameworks */,
                        );
                                2D60F61115657D0F00F2E3F9 /* libz.dylib in Frameworks */,
                                2DCF701A150E97C0002D5E8F /* libaslcommon.a in Frameworks */,
                        );
                08FB7794FE84155DC02AAC07 /* syslog */ = {
                        isa = PBXGroup;
                        children = (
                08FB7794FE84155DC02AAC07 /* syslog */ = {
                        isa = PBXGroup;
                        children = (
+                               2DEE8C421AE575AB007B5CBE /* CacheDelete.framework */,
+                               2DEE8C401AE575A2007B5CBE /* CoreFoundation.framework */,
                                505ACBA1108FD18400197086 /* aslcommon */,
                                503917691091404D0001165E /* aslmanager */,
                                503917C41091412B0001165E /* util */,
                                505ACBA1108FD18400197086 /* aslcommon */,
                                503917691091404D0001165E /* aslmanager */,
                                503917C41091412B0001165E /* util */,
                503917691091404D0001165E /* aslmanager */ = {
                        isa = PBXGroup;
                        children = (
                503917691091404D0001165E /* aslmanager */ = {
                        isa = PBXGroup;
                        children = (
+                               2DAF75541AE8610200054190 /* com.apple.activity_tracing.CacheDelete.plist */,
+                               2DEE8C441AE5798B007B5CBE /* cache_delete.c */,
+                               2DEE8C451AE5798B007B5CBE /* cache_delete.h */,
                                5039176B1091408B0001165E /* aslmanager.8 */,
                                5039176C1091408B0001165E /* aslmanager.c */,
                                5039176B1091408B0001165E /* aslmanager.8 */,
                                5039176C1091408B0001165E /* aslmanager.c */,
+                               2D30D27F1AE6C84200673818 /* daemon.c */,
+                               2D30D2801AE6C84200673818 /* daemon.h */,
                                5039176D1091408B0001165E /* com.apple.aslmanager.plist */,
                        );
                        name = aslmanager;
                                5039176D1091408B0001165E /* com.apple.aslmanager.plist */,
                        );
                        name = aslmanager;
                503917711091409F0001165E /* syslogd */ = {
                        isa = PBXGroup;
                        children = (
                503917711091409F0001165E /* syslogd */ = {
                        isa = PBXGroup;
                        children = (
-                               3FCCB5361749B53D00F8FEBC /* asl_sim.conf */,
+                               3FE6E8391A529FEF0075D75F /* asl.conf.ios */,
+                               2D9C4F131B3A29E700219FB3 /* com.apple.system.log */,
+                               3FE6E83A1A529FEF0075D75F /* asl.conf.osx */,
+                               3FCCB5361749B53D00F8FEBC /* asl.conf.ios_sim */,
+                               3FE6E83B1A529FEF0075D75F /* syslog.conf */,
                                503917A61091410E0001165E /* asl_action.c */,
                                2DB4DA0A125FC69A001CDC45 /* after_install.sh */,
                                503917A81091410E0001165E /* asl.conf.5 */,
                                503917A61091410E0001165E /* asl_action.c */,
                                2DB4DA0A125FC69A001CDC45 /* after_install.sh */,
                                503917A81091410E0001165E /* asl.conf.5 */,
                                50391764109140450001165E /* Frameworks */,
                                503A82631099037D00B0D08A /* Copy Manpage.8 */,
                                FCAC6D7410AB34C9008DEAC9 /* ShellScript */,
                                50391764109140450001165E /* Frameworks */,
                                503A82631099037D00B0D08A /* Copy Manpage.8 */,
                                FCAC6D7410AB34C9008DEAC9 /* ShellScript */,
+                               2D30D27D1AE6BBA000673818 /* Copy CacheDelete plist */,
                        );
                        buildRules = (
                        );
                        );
                        buildRules = (
                        );
 /* End PBXProject section */
 
 /* Begin PBXShellScriptBuildPhase section */
 /* End PBXProject section */
 
 /* Begin PBXShellScriptBuildPhase section */
-               3F5F5B9C17487ADB00C12281 /* Configuration */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 8;
-                       files = (
-                       );
-                       inputPaths = (
-                       );
-                       name = Configuration;
-                       outputPaths = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 1;
-                       shellPath = /bin/sh;
-                       shellScript = "mkdir -p ${DSTROOT}${INSTALL_PATH_PREFIX}/etc\ncp ${SRCROOT}/syslogd.tproj/asl_sim.conf ${DSTROOT}${INSTALL_PATH_PREFIX}/etc/asl.conf\n";
-               };
                3F900DB41938393C003CA7E6 /* Sim compat symlink */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                3F900DB41938393C003CA7E6 /* Sim compat symlink */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "set -e\n\nDESTDIR=\"$DSTROOT$INSTALL_PATH_PREFIX\"/System/Library/LaunchDaemons\ninstall -d -m 0755 -o root -g wheel -d \"$DESTDIR\"\ninstall -m 0644 -o root -g wheel \"$SRCROOT\"/aslmanager.tproj/com.apple.aslmanager.plist \"$DESTDIR\"\nplutil -convert binary1 \"$DESTDIR\"/com.apple.aslmanager.plist";
+                       shellScript = "set -e\n\nDESTDIR=\"$DSTROOT\"/System/Library/LaunchDaemons\ninstall -d -m 0755 -o root -g wheel -d \"$DESTDIR\"\ninstall -m 0644 -o root -g wheel \"$SRCROOT\"/aslmanager.tproj/com.apple.aslmanager.plist \"$DESTDIR\"\nplutil -convert binary1 \"$DESTDIR\"/com.apple.aslmanager.plist";
                        showEnvVarsInLog = 0;
                };
                FCF3762A10D2F47C00C0EC8D /* ShellScript */ = {
                        showEnvVarsInLog = 0;
                };
                FCF3762A10D2F47C00C0EC8D /* ShellScript */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               2D30D2811AE6C84200673818 /* daemon.c in Sources */,
                                5039176F1091408B0001165E /* aslmanager.c in Sources */,
                                5039176F1091408B0001165E /* aslmanager.c in Sources */,
+                               2DEE8C461AE5798B007B5CBE /* cache_delete.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                COPY_PHASE_STRIP = YES;
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                COPY_PHASE_STRIP = YES;
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+                               );
                                GCC_DYNAMIC_NO_PIC = NO;
                                OTHER_CFLAGS = (
                                        "-Wall",
                                        "-DINET6",
                                );
                                GCC_DYNAMIC_NO_PIC = NO;
                                OTHER_CFLAGS = (
                                        "-Wall",
                                        "-DINET6",
                                );
+                               OTHER_LDFLAGS = "";
                                PRODUCT_NAME = aslmanager;
                                ZERO_LINK = NO;
                        };
                                PRODUCT_NAME = aslmanager;
                                ZERO_LINK = NO;
                        };
index d54cd6ae27dad78e8dd312c3521c718f0890b33f..6fb20af8f37e85d7510dd394801fffed0a092227 100755 (executable)
@@ -1,35 +1,44 @@
-#! /bin/bash
-set -e
+#! /bin/bash -e -x
 
 
-if [ "${RC_ProjectName%_Sim}" != "${RC_ProjectName}" ] ; then
+if [[ "${PLATFORM_NAME}" =~ "simulator" ]] ; then
     PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd_sim.plist
     PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd_sim.plist
+    ASL_CONF="${SRCROOT}"/syslogd.tproj/asl.conf.ios_sim
+elif [[ "${PLATFORM_NAME}" == "macosx" ]] ; then
+    PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd.plist
+    ASL_CONF="${SRCROOT}"/syslogd.tproj/asl.conf.osx
+    SYSLOG_CONF="${SRCROOT}"/syslogd.tproj/syslog.conf
 else
     PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd.plist
 else
     PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd.plist
+    ASL_CONF="${SRCROOT}"/syslogd.tproj/asl.conf.ios
+    SYSLOG_CONF="${SRCROOT}"/syslogd.tproj/syslog.conf
+    SYSTEM_LOG_CONF="${SRCROOT}"/syslogd.tproj/com.apple.system.log
 fi
 
 fi
 
-DESTDIR="${DSTROOT}${INSTALL_PATH_PREFIX}"/System/Library/LaunchDaemons
+DESTDIR="${DSTROOT}"/private/etc
+install -d -m 0755 -o root -g wheel "${DESTDIR}"
+install -m 0644 -o root -g wheel "${ASL_CONF}" "${DESTDIR}"/asl.conf
+if [[ -n "${SYSLOG_CONF}" ]] ; then
+    install -m 0644 -o root -g wheel "${SYSLOG_CONF}" "${DESTDIR}"
+fi
 
 
+DESTDIR="${DSTROOT}"/System/Library/LaunchDaemons
 install -d -m 0755 -o root -g wheel "${DESTDIR}"
 install -m 0644 -o root -g wheel "${PLIST}" "${DESTDIR}"/com.apple.syslogd.plist
 plutil -convert binary1 "${DESTDIR}"/com.apple.syslogd.plist
 
 install -d -m 0755 -o root -g wheel "${DESTDIR}"
 install -m 0644 -o root -g wheel "${PLIST}" "${DESTDIR}"/com.apple.syslogd.plist
 plutil -convert binary1 "${DESTDIR}"/com.apple.syslogd.plist
 
-if [ "${RC_ProjectName%_Sim}" != "${RC_ProjectName}" ] ; then
+if [[ "${PLATFORM_NAME}" =~ "simulator" ]] ; then
     exit 0
 fi
 
 install -d -m 0755 -o root -g wheel "$DSTROOT"/private/var/log/asl
 
     exit 0
 fi
 
 install -d -m 0755 -o root -g wheel "$DSTROOT"/private/var/log/asl
 
-PRODUCT=$(xcodebuild -sdk "${SDKROOT}" -version PlatformPath | head -1 | sed 's,^.*/\([^/]*\)\.platform$,\1,')
-
-if [ ${SDKROOT}x = x ]; then
-       PRODUCT=MacOSX
-fi
-
-if [ ${PRODUCT}x = x ]; then
-       PRODUCT=MacOSX
-fi
-
-if [ ${PRODUCT} = iPhone ]; then
+if [[ "${PLATFORM_NAME}" != "macosx" ]]; then
     install -d -m 0755 -o root -g wheel "$DSTROOT"/usr/share/sandbox
     install -m 0644 -o root -g wheel "$SRCROOT"/syslogd.tproj/syslogd.sb "$DSTROOT"/usr/share/sandbox
 fi
     install -d -m 0755 -o root -g wheel "$DSTROOT"/usr/share/sandbox
     install -m 0644 -o root -g wheel "$SRCROOT"/syslogd.tproj/syslogd.sb "$DSTROOT"/usr/share/sandbox
 fi
+
+if ! [[ "${PLATFORM_NAME}" =~ "simulator" || "${PLATFORM_NAME}" == "macosx" ]]; then
+       DESTDIR="${DSTROOT}"/usr/local/etc/asl
+       install -d -m 0755 -o root -g wheel "${DESTDIR}"
+       install -m 0644 -o root -g wheel "${SYSTEM_LOG_CONF}" "${DESTDIR}"/com.apple.system.log
+fi
index 5d6e115e87d03200201663fbe8e9cf584cd47ac3..4402046793fa61503cfa0bc76831dff8752a04ae 100644 (file)
@@ -523,63 +523,26 @@ The FILE ROTATION section describes this in detail.
 .It rotate=NAME_STYLE
 Enables log file rotation and specifies the file naming scheme for rotated files.
 This option does not apply to ASL directories.
 .It rotate=NAME_STYLE
 Enables log file rotation and specifies the file naming scheme for rotated files.
 This option does not apply to ASL directories.
-Four styles are supported:
-.Pp
-.Bl -tag -width "local-basic" -compact -indent
-.It sec
-Rotated file names are of the form
-.Dq example.log.T1340607600 .
-The file names include the creation time of the file in seconds since the epoch.
-.Pp
-.It utc
-Rotated file names are in ISO 8601 extended format, for example
-.Dq example.log.2012-06-24T07:00:00Z .
-The file names includes its creation time as a UTC date and time.
-.Pp
-.It utc-basic
-Rotated file names are in ISO 8601 basic format, for example
-.Dq example.log.20120624T070000Z .
-The file names includes its creation time as a UTC date and time.
-.Pp
-.It local
-Rotated file names are in ISO 8601 extended format, for example
-.Dq example.log.2012-06-24T07:00:00-7 .
-The file names includes its creation time as date and time in the local time zone.
-The local timezone offset is included as a trailing part of the name.
-.Pp
-.It local-basic
-Rotated file names are in ISO 8601 basic format, for example
-.Dq example.log.20120624T070000-07 .
-The file names includes its creation time as date and time in the local time zone.
-The local timezone offset is included as a trailing part of the name.
-.Pp
-.It seq
-Rotated file names are of the form
-.Dq example.log.N
-where N is an integer sequence number.
-Files are re-numbered on each rotation so that the 
-.Dq 0
-file is the most recent.
-.El
+NAME_STYLE may either be a simple time-stamp style:
+.Dq sec ,
+.Dq utc ,
+.Dq utc-basic ,
+.Dq local ,
+.Dq local-basic ,
+or
+.Dq seq ;
+or the value may contain the file's base name, a file name extension, and one of the time-stame styles.
+For example
+.Dq example.seq.log
+or
+.Dq example.log.utc-basic.
+A detailed description of name styles may be found in the FILE ROTATION section below.
 .Pp
 If the option 
 .Dq rotate
 appears without a value, the naming style defaults to
 .Dq "sec" .
 .Pp
 .Pp
 If the option 
 .Dq rotate
 appears without a value, the naming style defaults to
 .Dq "sec" .
 .Pp
-Note that using the local timezone for timestamped files may cause odd behavior on highly-mobile systems.
-.Nm aslmanager
-will delete files after a specified time-to-live (see below).
-The age of the file is determined by the file name.
-If files are created in different timezones but saved with a non-absolute timestamp,
-the age calculation may result in some files being considered older or newer than they are in reality.
-.Pp
-Also note that sequenced files (using the
-.Dq seq
-style) will initially be checkpointed using a file name containing a timestamp in seconds.
-.Nm aslmanager
-will re-sequence the files when it scans for checkpoint files.
-.Pp
 .It ttl=DAYS
 Specifies the number of days that older versions of rotated files should be allowed to remain in the filesystem.
 Rotated files older than this limit are deleted.
 .It ttl=DAYS
 Specifies the number of days that older versions of rotated files should be allowed to remain in the filesystem.
 Rotated files older than this limit are deleted.
@@ -605,6 +568,13 @@ Enables gzip file compression for rotated log files.
 When compressed, the extension 
 .Dq .gz
 is appended to the file name.
 When compressed, the extension 
 .Dq .gz
 is appended to the file name.
+When the output is an ASL directory, data files are compressed after midnight local time.
+This means that messages written in the current day will be readable using
+.Nm syslog Fl d
+or using the
+.Xr asl 3
+API.
+Messages in compressed data files will not be available until the files are un-compressed.
 .Pp
 .It file_max=SIZE
 Limits the size of an active log file.
 .Pp
 .It file_max=SIZE
 Limits the size of an active log file.
@@ -629,17 +599,130 @@ Specifies a size limit for the total of all rotated versions of a file.
 .Nm aslmanager
 will delete rotated files, oldest first, to reduce the total below the limit.
 SIZE may be specified in the same format as the file_max option.
 .Nm aslmanager
 will delete rotated files, oldest first, to reduce the total below the limit.
 SIZE may be specified in the same format as the file_max option.
+.Pp
+.It basestamp
+Causes
+.Nm syslogd
+to add a timestamp to the file name when it is created.
+For example,
+.Pp
+.Dl
+> example.log rotate=utc-basic basestamp
+.Pp
+will result in syslogd writing to, e.g.
+.Dq example.log.20120625T070000Z
+rather than to
+.Dq example.log .
+Note that this option does nothing with sequenced (``seq'') files.
+.Pp
+.It symlink
+This option may only be used together with the basestamp option.
+It causes
+.Nm syslogd
+to create a symlink with the unstamped file name to the currently active log file.
+For example,
+.Pp
+.Dl
+> example.log rotate=sec basestamp symlink
+.Pp
+will result in syslogd writing to, e.g.
+.Dq example.log.T1340607600 ,
+and creating a sybolic link from
+.Dq example.log
+to the active file.
+.Pp
 .El
 .Ss FILE ROTATION
 .Nm syslogd
 and
 .Nm aslmanager
 .El
 .Ss FILE ROTATION
 .Nm syslogd
 and
 .Nm aslmanager
-work together to automatically provide all the features of file rotation.
-However, it is useful to understand how the process works.
+work together to provide the features of file rotation.
 This section describes the file rotation options that may be used in /etc/asl.conf
 or an ASL Output Module configuration file,
 together with a description of how the system works to support those features.
 .Pp
 This section describes the file rotation options that may be used in /etc/asl.conf
 or an ASL Output Module configuration file,
 together with a description of how the system works to support those features.
 .Pp
+File rotation or file rolling is enabled by the
+.Dq rotate
+output configuration option.
+It is typically specificed with a value which specifies the naming sytle for rotated files.
+Name styles may simply be a timestamp format, which is appended to the filename.
+.Pp
+.Bl -tag -width "local-basic" -compact -indent
+.It sec
+Rotated file names are of the form
+.Dq example.log.T1340607600 .
+The file names include the creation time of the file in seconds since the epoch.
+.Pp
+.It utc
+Rotated file names are in ISO 8601 extended format, for example
+.Dq example.log.2012-06-24T07:00:00Z .
+The file names includes its creation time as a UTC date and time.
+.Pp
+.It utc-basic
+Rotated file names are in ISO 8601 basic format, for example
+.Dq example.log.20120624T070000Z .
+The file names includes its creation time as a UTC date and time.
+.Pp
+.It local
+Rotated file names are in ISO 8601 extended format, for example
+.Dq example.log.2012-06-24T07:00:00-7 .
+The file names includes its creation time as date and time in the local time zone.
+The local timezone offset is included as a trailing part of the name.
+The value
+.Dq lcl
+is an alias for
+.Dq local .
+.Pp
+.It local-basic
+Rotated file names are in ISO 8601 basic format, for example
+.Dq example.log.20120624T070000-07 .
+The file names includes its creation time as date and time in the local time zone.
+The local timezone offset is included as a trailing part of the name.
+The value
+.Dq lcl-basic
+is an alias for
+.Dq local-basic .
+.Pp
+.It seq
+Rotated file names are of the form
+.Dq example.log.N
+where N is an integer sequence number.
+Files are re-numbered on each rotation so that the
+.Dq 0
+file is the most recent.
+.El
+.Pp
+Note that using the local timezone for timestamped files may cause odd behavior on highly mobile systems.
+.Nm aslmanager
+will delete files after a specified time-to-live (see below).
+The age of the file is determined by the file name.
+If files are created in different timezones but saved with a non-absolute timestamp,
+the age calculation may result in some files being considered older or newer than they are in reality.
+.Pp
+Also note that sequenced files (using the
+.Dq seq
+style) will initially be checkpointed using a file name containing a timestamp in seconds.
+.Nm aslmanager
+will re-sequence the files when it scans for checkpoint files.
+.Pp
+.Pp
+Alternatively, the name style may be have two or three components.
+The first component is the
+.Dq base
+name of the file, with no filename extension.
+The base name may be followed by a timestamp format and optionally by a filename extension,
+or the base name may be followed by an extension (the extension is optional) and a timestamp format.
+These components must be separated by a dot character.
+.Pp
+For example, this output configuration line specifies that the output file
+.Dq example.log
+should be rotated to create the files
+.Dq example.0.log ,
+.Dq example.1.log ,
+and so on.
+.Pp
+.Dl > example.log rotate=example.seq.log
+.Pp
 If a file is marked for rotation,
 .Nm syslogd
 will close the file at the start of a new day or when the file exceeds its 
 If a file is marked for rotation,
 .Nm syslogd
 will close the file at the start of a new day or when the file exceeds its 
@@ -647,8 +730,9 @@ will close the file at the start of a new day or when the file exceeds its
 size limit.
 At that point,
 .Nm syslogd
 size limit.
 At that point,
 .Nm syslogd
-renames the file and starts a new file to continue logging.
-The old file is renamed with the file's creation time included in its name.
+renames the file with the file's creation time included in its name
+(unless the basestamp option is present, in which case the file's creation time
+is already included in the filename) and starts a new file to continue logging.
 This operation is called checkpointing the file.
 .Pp
 For example,
 This operation is called checkpointing the file.
 .Pp
 For example,
diff --git a/syslogd.tproj/asl.conf.ios b/syslogd.tproj/asl.conf.ios
new file mode 100644 (file)
index 0000000..ae10c60
--- /dev/null
@@ -0,0 +1,30 @@
+##
+# configuration file for syslogd and aslmanager
+##
+
+# aslmanager logs
+> /var/log/asl/Logs/aslmanager external style=lcl-b ttl=2
+
+# authpriv messages are root/admin readable
+? [= Facility authpriv] access 0 80
+
+# remoteauth critical, alert, and emergency messages are root/admin readable
+? [= Facility remoteauth] [<= Level critical] access 0 80
+
+# broadcast emergency messages
+? [= Level emergency] broadcast
+
+# save kernel [PID 0] and launchd [PID 1] messages
+? [<= PID 1] store
+
+# ignore "internal" facility
+? [= Facility internal] ignore
+
+# save everything from emergency to notice
+? [<= Level notice] store
+
+# Specify owner, group, and access bits for mobile-owned log directories
+> /var/mobile/Library uid=501 gid=501 mode=0700
+> /var/mobile/Library/Logs uid=501 gid=501 mode=0755
+> /var/mobile/Library/Logs/CrashReporter uid=501 gid=501 mode=0755
+> /var/mobile/Library/Logs/CrashReporter/DiagnosticLogs uid=501 gid=501 mode=0755
diff --git a/syslogd.tproj/asl.conf.ios_sim b/syslogd.tproj/asl.conf.ios_sim
new file mode 100644 (file)
index 0000000..9ba0797
--- /dev/null
@@ -0,0 +1,33 @@
+##
+# configuration file for syslogd and aslmanager in the iOS Simulator
+##
+
+# redirect com.apple.message.domain to $ENV(SIMULATOR_LOG_ROOT)/DiagnosticMessages
+? [T com.apple.message.domain] store_dir $ENV(SIMULATOR_LOG_ROOT)/DiagnosticMessages
+
+# redirect com.apple.performance* messages to $ENV(SIMULATOR_LOG_ROOT)/performance
+? [A= Facility com.apple.performance] store_dir $ENV(SIMULATOR_LOG_ROOT)/performance
+
+# redirect com.apple.eventmonitor* messages to $ENV(SIMULATOR_LOG_ROOT)/eventmonitor
+? [A= Facility com.apple.eventmonitor] store_dir $ENV(SIMULATOR_LOG_ROOT)/eventmonitor
+
+# ignore "internal" facility
+? [= Facility internal] ignore
+
+# save everything from emergency to notice
+? [<= Level notice] store
+
+# install messages get saved only in install.log
+? [= Facility install] file $ENV(SIMULATOR_LOG_ROOT)/install.log format=bsd file_max=5M all_max=50M
+? [= Facility install] ignore
+
+> $ENV(SIMULATOR_LOG_ROOT)/system.log mode=0640 format=bsd rotate=seq compress file_max=5M all_max=50M
+
+# emergency - notice get saved in system.log
+? [<= Level notice] file $ENV(SIMULATOR_LOG_ROOT)/system.log
+
+# Facility auth to level info gets saved in system.log
+? [= Facility auth] [<= Level info] file $ENV(SIMULATOR_LOG_ROOT)/system.log
+
+# Facility authpriv gets saved in system.log
+? [= Facility authpriv] file $ENV(SIMULATOR_LOG_ROOT)/system.log
diff --git a/syslogd.tproj/asl.conf.osx b/syslogd.tproj/asl.conf.osx
new file mode 100644 (file)
index 0000000..ef9dc9b
--- /dev/null
@@ -0,0 +1,34 @@
+##
+# configuration file for syslogd and aslmanager
+##
+
+# aslmanager logs
+> /var/log/asl/Logs/aslmanager external style=lcl-b ttl=2
+
+# authpriv messages are root/admin readable
+? [= Facility authpriv] access 0 80
+
+# remoteauth critical, alert, and emergency messages are root/admin readable
+? [= Facility remoteauth] [<= Level critical] access 0 80
+
+# broadcast emergency messages
+? [= Level emergency] broadcast
+
+# save kernel [PID 0] and launchd [PID 1] messages
+? [<= PID 1] store
+
+# ignore "internal" facility
+? [= Facility internal] ignore
+
+# save everything from emergency to notice
+? [<= Level notice] store
+
+# Rules for /var/log/system.log
+> system.log mode=0640 format=bsd rotate=seq compress file_max=5M all_max=50M
+? [= Sender kernel] file system.log
+? [<= Level notice] file system.log
+? [= Facility auth] [<= Level info] file system.log
+? [= Facility authpriv] [<= Level info] file system.log
+
+# Facility com.apple.alf.logging gets saved in appfirewall.log
+? [= Facility com.apple.alf.logging] file appfirewall.log file_max=5M all_max=50M
index b33d58275d28cf79af32ff42f41293cbc0532a5d..ca0d19d713577a8169ee20388190440a7d2f5fbd 100644 (file)
@@ -500,7 +500,7 @@ _asl_dir_today_close(asl_out_rule_t *r)
        if (as_data->pending != 0)
        {
                char *str = NULL;
        if (as_data->pending != 0)
        {
                char *str = NULL;
-               asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL Store %s was closed with %d pending messages]", global.pid, r->dst->fname, as_data->pending);
+               asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL Store %s was closed with %d pending messages]", global.pid, r->dst->current_name, as_data->pending);
                internal_log_message(str);
                free(str);
        }
                internal_log_message(str);
                free(str);
        }
@@ -529,8 +529,8 @@ _asl_dir_today_close(asl_out_rule_t *r)
        as_data->p_month = 0;
        as_data->p_day = 0;
 
        as_data->p_month = 0;
        as_data->p_day = 0;
 
-       free(r->dst->fname);
-       r->dst->fname = NULL;
+       free(r->dst->current_name);
+       r->dst->current_name = NULL;
 
        as_data->aslfile = NULL;
 }
 
        as_data->aslfile = NULL;
 }
@@ -541,22 +541,22 @@ _asl_dir_today_close(asl_out_rule_t *r)
 static int
 _act_checkpoint(asl_out_rule_t *r, uint32_t force)
 {
 static int
 _act_checkpoint(asl_out_rule_t *r, uint32_t force)
 {
-       char tmpfname[MAXPATHLEN], *fn;
+       char tmpcurrent_name[MAXPATHLEN], *fn;
 
        if (r == NULL) return 0;
        if (r->dst == NULL) return 0;
 
 
        if (r == NULL) return 0;
        if (r->dst == NULL) return 0;
 
-       fn = r->dst->fname;
+       fn = r->dst->current_name;
        if (fn == NULL)
        {
                if (r->dst->path == NULL) return 0;
        if (fn == NULL)
        {
                if (r->dst->path == NULL) return 0;
-               asl_make_dst_filename(r->dst, tmpfname, sizeof(tmpfname));
-               fn = tmpfname;
+               asl_dst_make_current_name(r->dst, 0, tmpcurrent_name, sizeof(tmpcurrent_name));
+               fn = tmpcurrent_name;
        }
 
        if ((force == CHECKPOINT_TEST) && (r->dst->file_max == 0)) return 0;
 
        }
 
        if ((force == CHECKPOINT_TEST) && (r->dst->file_max == 0)) return 0;
 
-       if ((r->dst->size == 0) || (r->dst->stamp == 0))
+       if ((r->dst->size == 0) || (r->dst->timestamp == 0))
        {
                struct stat sb;
 
        {
                struct stat sb;
 
@@ -568,8 +568,8 @@ _act_checkpoint(asl_out_rule_t *r, uint32_t force)
                        return -1;
                }
 
                        return -1;
                }
 
-               if (r->dst->stamp == 0) r->dst->stamp = sb.st_birthtimespec.tv_sec;
-               if (r->dst->stamp == 0) r->dst->stamp = sb.st_mtimespec.tv_sec;
+               if (r->dst->timestamp == 0) r->dst->timestamp = sb.st_birthtimespec.tv_sec;
+               if (r->dst->timestamp == 0) r->dst->timestamp = sb.st_mtimespec.tv_sec;
                r->dst->size = sb.st_size;
        }
        
                r->dst->size = sb.st_size;
        }
        
@@ -583,19 +583,21 @@ _act_checkpoint(asl_out_rule_t *r, uint32_t force)
        {
                char srcpath[MAXPATHLEN];
                char dstpath[MAXPATHLEN];
        {
                char srcpath[MAXPATHLEN];
                char dstpath[MAXPATHLEN];
-               char tstamp[32];
-
-               if (r->dst->stamp == 0) r->dst->stamp = time(NULL);
-               asl_make_timestamp(r->dst->stamp, r->dst->flags, tstamp, sizeof(tstamp));
 
                snprintf(srcpath, sizeof(srcpath), "%s", fn);
 
                snprintf(srcpath, sizeof(srcpath), "%s", fn);
-               snprintf(dstpath, sizeof(dstpath), "%s.%s", fn, tstamp);
+
+               r->dst->timestamp = time(NULL);
+               asl_dst_make_current_name(r->dst, MODULE_FLAG_BASESTAMP, dstpath, sizeof(dstpath));
 
                _act_dst_close(r, DST_CLOSE_CHECKPOINT);
 
                _act_dst_close(r, DST_CLOSE_CHECKPOINT);
-               rename(srcpath, dstpath);
+               if (strneq(srcpath, dstpath))
+               {
+                       rename(srcpath, dstpath);
+                       asldebug("CHECKPOINT RENAME %s %s\n", srcpath, dstpath);
+               }
        }
 
        }
 
-       r->dst->stamp = 0;
+       r->dst->timestamp = 0;
        r->dst->size = 0;
        return 1;
 }
        r->dst->size = 0;
        return 1;
 }
@@ -640,7 +642,7 @@ _asl_dir_today_open(asl_out_rule_t *r, const time_t *tick)
 
        /* checks file_max and closes if required */
        status = _act_checkpoint(r, CHECKPOINT_TEST);
 
        /* checks file_max and closes if required */
        status = _act_checkpoint(r, CHECKPOINT_TEST);
-       if (status == 1) trigger_aslmanager();
+       if (status == 1) asl_trigger_aslmanager();
 
        if (as_data->aslfile != NULL)
        {
 
        if (as_data->aslfile != NULL)
        {
@@ -663,16 +665,16 @@ _asl_dir_today_open(asl_out_rule_t *r, const time_t *tick)
                        tick = (const time_t *)&now;
                }
 
                        tick = (const time_t *)&now;
                }
 
-               asl_make_timestamp(now, r->dst->flags, tstamp, sizeof(tstamp));
-               asprintf(&(r->dst->fname), "%s/%s.asl", r->dst->path, tstamp);
+               asl_make_timestamp(now, r->dst->style_flags, tstamp, sizeof(tstamp));
+               asprintf(&(r->dst->current_name), "%s/%s.asl", r->dst->path, tstamp);
        }
        else
        {
        }
        else
        {
-               asprintf(&(r->dst->fname), "%s/%d.%02d.%02d.asl", r->dst->path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
+               asprintf(&(r->dst->current_name), "%s/%d.%02d.%02d.asl", r->dst->path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
        }
 
 
        }
 
 
-       if (r->dst->fname == NULL)
+       if (r->dst->current_name == NULL)
        {
                asldebug("_asl_dir_today_open: asprintf error %s\n", strerror(errno));
                return -1;
        {
                asldebug("_asl_dir_today_open: asprintf error %s\n", strerror(errno));
                return -1;
@@ -687,22 +689,22 @@ _asl_dir_today_open(asl_out_rule_t *r, const time_t *tick)
 #endif
 
        mask = umask(0);
 #endif
 
        mask = umask(0);
-       status = asl_file_open_write(r->dst->fname, (r->dst->mode & 00666), uid, gid, &(as_data->aslfile));
+       status = asl_file_open_write(r->dst->current_name, (r->dst->mode & 00666), uid, gid, &(as_data->aslfile));
        umask(mask);
 
        if (status != ASL_STATUS_OK)
        {
        umask(mask);
 
        if (status != ASL_STATUS_OK)
        {
-               asldebug("_asl_dir_today_open: asl_file_open_write %s error %s\n", r->dst->fname, asl_core_error(status));
-               free(r->dst->fname);
-               r->dst->fname = NULL;
+               asldebug("_asl_dir_today_open: asl_file_open_write %s error %s\n", r->dst->current_name, asl_core_error(status));
+               free(r->dst->current_name);
+               r->dst->current_name = NULL;
                return -1;
        }
 
        if (fseek(as_data->aslfile->store, 0, SEEK_END) != 0)
        {
                return -1;
        }
 
        if (fseek(as_data->aslfile->store, 0, SEEK_END) != 0)
        {
-               asldebug("_asl_dir_today_open: fseek %s error %s\n", r->dst->fname, strerror(errno));
-               free(r->dst->fname);
-               r->dst->fname = NULL;
+               asldebug("_asl_dir_today_open: fseek %s error %s\n", r->dst->current_name, strerror(errno));
+               free(r->dst->current_name);
+               r->dst->current_name = NULL;
                return -1;
        }
 
                return -1;
        }
 
@@ -729,7 +731,7 @@ _asl_dir_today_open(asl_out_rule_t *r, const time_t *tick)
                dispatch_resume(as_data->aslfile_monitor);
        }
 
                dispatch_resume(as_data->aslfile_monitor);
        }
 
-       asldebug("_asl_dir_today_open ASL file %s fd %d\n", r->dst->fname, fd);
+       asldebug("_asl_dir_today_open ASL file %s fd %d\n", r->dst->current_name, fd);
 
        return 0;
 }
 
        return 0;
 }
@@ -746,7 +748,7 @@ _asl_file_close(asl_out_rule_t *r)
        if (af_data->pending != 0)
        {
                char *str = NULL;
        if (af_data->pending != 0)
        {
                char *str = NULL;
-               asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL File %s was closed with %d pending messages]", global.pid, r->dst->fname, af_data->pending);
+               asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL File %s was closed with %d pending messages]", global.pid, r->dst->current_name, af_data->pending);
                internal_log_message(str);
                free(str);
        }
                internal_log_message(str);
                free(str);
        }
@@ -796,18 +798,18 @@ _asl_file_open(asl_out_rule_t *r)
        fd = _act_file_create_open(r->dst);
        if (fd < 0)
        {
        fd = _act_file_create_open(r->dst);
        if (fd < 0)
        {
-               asldebug("_asl_file_open: _act_file_create_open %s failed %d %s\n", r->dst->fname, errno, strerror(errno));
+               asldebug("_asl_file_open: _act_file_create_open %s failed %d %s\n", r->dst->current_name, errno, strerror(errno));
                return -1;
        }
 
        close(fd);
 
                return -1;
        }
 
        close(fd);
 
-       if (r->dst->fname == NULL) return -1;
+       if (r->dst->current_name == NULL) return -1;
 
 
-       status = asl_file_open_write(r->dst->fname, 0, -1, -1, &(af_data->aslfile));
+       status = asl_file_open_write(r->dst->current_name, 0, -1, -1, &(af_data->aslfile));
        if (status != ASL_STATUS_OK)
        {
        if (status != ASL_STATUS_OK)
        {
-               asldebug("_asl_file_open: asl_file_open_write %s failed %d %s\n", r->dst->fname, errno, strerror(errno));
+               asldebug("_asl_file_open: asl_file_open_write %s failed %d %s\n", r->dst->current_name, errno, strerror(errno));
                return -1;
        }
 
                return -1;
        }
 
@@ -830,7 +832,7 @@ _asl_file_open(asl_out_rule_t *r)
                dispatch_resume(af_data->monitor);
        }
 
                dispatch_resume(af_data->monitor);
        }
 
-       asldebug("_asl_file_open ASL file %s fd %d\n", r->dst->fname, fd);
+       asldebug("_asl_file_open ASL file %s fd %d\n", r->dst->current_name, fd);
        return 0;
 }
 
        return 0;
 }
 
@@ -843,7 +845,7 @@ _text_file_close(asl_out_rule_t *r)
        if (f_data->pending != 0)
        {
                char *str = NULL;
        if (f_data->pending != 0)
        {
                char *str = NULL;
-               asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message File %s was closed with %d pending messages]", global.pid, r->dst->fname, f_data->pending);
+               asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message File %s was closed with %d pending messages]", global.pid, r->dst->current_name, f_data->pending);
                internal_log_message(str);
                free(str);
        }
                internal_log_message(str);
                free(str);
        }
@@ -969,12 +971,12 @@ _act_dst_close(asl_out_rule_t *r, int why)
        }
        else if (r->action == ACTION_ASL_FILE)
        {
        }
        else if (r->action == ACTION_ASL_FILE)
        {
-               asldebug("_act_dst_close: %s ASL FILE %s\n", why_str[why], (r->dst->fname == NULL) ? r->dst->path : r->dst->fname);
+               asldebug("_act_dst_close: %s ASL FILE %s\n", why_str[why], (r->dst->current_name == NULL) ? r->dst->path : r->dst->current_name);
                _asl_file_close(r);
        }
        else if (r->action == ACTION_FILE)
        {
                _asl_file_close(r);
        }
        else if (r->action == ACTION_FILE)
        {
-               asldebug("_act_dst_close: %s FILE %s\n", why_str[why], (r->dst->fname == NULL) ? r->dst->path : r->dst->fname);
+               asldebug("_act_dst_close: %s FILE %s\n", why_str[why], (r->dst->current_name == NULL) ? r->dst->path : r->dst->current_name);
                _text_file_close(r);
        }
 }
                _text_file_close(r);
        }
 }
@@ -1181,7 +1183,7 @@ _act_store_file(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
                {
                        r->dst->size = af_data->aslfile->file_size;
 
                {
                        r->dst->size = af_data->aslfile->file_size;
 
-                       if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) trigger_aslmanager();
+                       if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) asl_trigger_aslmanager();
                }
        }
 
                }
        }
 
@@ -1337,7 +1339,7 @@ _send_repeat_msg(asl_out_rule_t *r)
 
        if ((status < 0) || (status < len))
        {
 
        if ((status < 0) || (status < len))
        {
-               asldebug("%s: error writing repeat message (%s): %s\n", MY_ID, r->dst->fname, strerror(errno));
+               asldebug("%s: error writing repeat message (%s): %s\n", MY_ID, r->dst->current_name, strerror(errno));
                return -1;
        }
 
                return -1;
        }
 
@@ -1449,7 +1451,7 @@ _act_file_checkpoint_all(uint32_t force)
                if (_act_file_checkpoint(m, NULL, force) > 0) did_checkpoint = 1;
        }
 
                if (_act_file_checkpoint(m, NULL, force) > 0) did_checkpoint = 1;
        }
 
-       trigger_aslmanager();
+       asl_trigger_aslmanager();
 
        return did_checkpoint;
 }
 
        return did_checkpoint;
 }
@@ -1466,6 +1468,8 @@ _act_file_final(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
        char *str;
        time_t now;
 
        char *str;
        time_t now;
 
+       if (r == NULL) return;
+       if (r->dst == NULL) return;
        if (r->dst->private == NULL) return;
 
        f_data = (asl_action_file_data_t *)r->dst->private;
        if (r->dst->private == NULL) return;
 
        f_data = (asl_action_file_data_t *)r->dst->private;
@@ -1559,7 +1563,7 @@ _act_file_final(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
                        size_t bytes = write(f_data->fd, str, len - 1);
                        if (bytes > 0) r->dst->size += bytes;
 
                        size_t bytes = write(f_data->fd, str, len - 1);
                        if (bytes > 0) r->dst->size += bytes;
 
-                       if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) trigger_aslmanager();
+                       if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) asl_trigger_aslmanager();
                }
        }
 
                }
        }
 
@@ -1702,7 +1706,7 @@ _asl_out_process_message(asl_out_module_t *m, asl_msg_t *msg)
 }
 
 void
 }
 
 void
-asl_out_message(asl_msg_t *msg)
+asl_out_message(asl_msg_t *msg, int64_t msize)
 {
        OSAtomicIncrement32(&global.asl_queue_count);
        asl_msg_retain(msg);
 {
        OSAtomicIncrement32(&global.asl_queue_count);
        asl_msg_retain(msg);
@@ -1744,6 +1748,14 @@ asl_out_message(asl_msg_t *msg)
                p = asl_msg_get_val_for_key(msg, ASL_KEY_FINAL_NOTIFICATION);
                if (p != NULL) asl_msg_set_key_val(msg, ASL_KEY_FREE_NOTE, p);
 
                p = asl_msg_get_val_for_key(msg, ASL_KEY_FINAL_NOTIFICATION);
                if (p != NULL) asl_msg_set_key_val(msg, ASL_KEY_FREE_NOTE, p);
 
+               /* chain to the next output module (done this way to make queue size accounting easier */
+#if !TARGET_IPHONE_SIMULATOR
+               if (global.bsd_out_enabled) bsd_out_message(msg, msize);
+               else OSAtomicAdd64(-1ll * msize, &global.memory_size);
+#else
+               OSAtomicAdd64(-1ll * msize, &global.memory_size);
+#endif
+
                asl_msg_release(msg);
                OSAtomicDecrement32(&global.asl_queue_count);
 
                asl_msg_release(msg);
                OSAtomicDecrement32(&global.asl_queue_count);
 
diff --git a/syslogd.tproj/asl_sim.conf b/syslogd.tproj/asl_sim.conf
deleted file mode 100644 (file)
index e2cc06a..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-##
-# configuration file for syslogd and aslmanager in the iOS Simulator
-##
-
-# redirect com.apple.message.domain to $ENV(SIMULATOR_LOG_ROOT)/DiagnosticMessages
-? [T com.apple.message.domain] store_dir $ENV(SIMULATOR_LOG_ROOT)/DiagnosticMessages
-
-# redirect com.apple.performance* messages to $ENV(SIMULATOR_LOG_ROOT)/performance
-? [A= Facility com.apple.performance] store_dir $ENV(SIMULATOR_LOG_ROOT)/performance
-
-# redirect com.apple.eventmonitor* messages to $ENV(SIMULATOR_LOG_ROOT)/eventmonitor
-? [A= Facility com.apple.eventmonitor] store_dir $ENV(SIMULATOR_LOG_ROOT)/eventmonitor
-
-# broadcast emergency messages
-? [= Level emergency] broadcast
-
-# ignore "internal" facility
-? [= Facility internal] ignore
-
-# save everything from emergency to notice
-? [<= Level notice] store
-
-# install messages get saved only in install.log
-? [= Facility install] file $ENV(SIMULATOR_LOG_ROOT)/install.log format=bsd file_max=5M all_max=50M
-? [= Facility install] ignore
-
-> $ENV(SIMULATOR_LOG_ROOT)/system.log mode=0640 format=bsd rotate=seq compress file_max=5M all_max=50M
-
-# emergency - notice get saved in system.log
-? [<= Level notice] file $ENV(SIMULATOR_LOG_ROOT)/system.log
-
-# Facility auth to level info gets saved in system.log
-? [= Facility auth] [<= Level info] file $ENV(SIMULATOR_LOG_ROOT)/system.log
-
-# Facility authpriv gets saved in system.log
-? [= Facility authpriv] file $ENV(SIMULATOR_LOG_ROOT)/system.log
index 935b01a67b12f693eaa4d1582bdd82b24b1a24d9..9cd9d430c8d4fbd9994e7553afaa2325107e5344 100644 (file)
@@ -658,7 +658,7 @@ _bsd_match_and_send(asl_msg_t *msg)
 }
 
 void
 }
 
 void
-bsd_out_message(asl_msg_t *msg)
+bsd_out_message(asl_msg_t *msg, int64_t msize)
 {
        if (msg == NULL) return;
 
 {
        if (msg == NULL) return;
 
@@ -668,6 +668,10 @@ bsd_out_message(asl_msg_t *msg)
        dispatch_async(bsd_out_queue, ^{
                _bsd_match_and_send(msg);
                asl_msg_release((asl_msg_t *)msg);
        dispatch_async(bsd_out_queue, ^{
                _bsd_match_and_send(msg);
                asl_msg_release((asl_msg_t *)msg);
+
+               /* end of the output module chain (after asl) - decrement global memory stats */
+               OSAtomicAdd64(-1ll * msize, &global.memory_size);
+
                OSAtomicDecrement32(&global.bsd_queue_count);
        });
 }
                OSAtomicDecrement32(&global.bsd_queue_count);
        });
 }
diff --git a/syslogd.tproj/com.apple.system.log b/syslogd.tproj/com.apple.system.log
new file mode 100644 (file)
index 0000000..4903a9d
--- /dev/null
@@ -0,0 +1,8 @@
+# Rules for /var/log/system.log
+# This file is installed in /usr/local/etc/asl on iOS for Apple Internal
+#
+> /var/log/system.log mode=0640 format=bsd rotate=system.seq.log compress file_max=5M all_max=50M
+? [= Sender kernel] file system.log
+? [<= Level notice] file system.log
+? [= Facility auth] [<= Level info] file system.log
+? [= Facility authpriv] [<= Level info] file system.log
index 5122d6d619efc06523b184aba4013a44f00d1f0a..5c87c222771d61fa765b42e5b39c722123f54c16 100644 (file)
 #include <libkern/OSAtomic.h>
 #include <libproc.h>
 #include <uuid/uuid.h>
 #include <libkern/OSAtomic.h>
 #include <libproc.h>
 #include <uuid/uuid.h>
+#include <asl_private.h>
 #include "daemon.h"
 
 #define LIST_SIZE_DELTA 256
 #include "daemon.h"
 
 #define LIST_SIZE_DELTA 256
+#define STATS_TABLE_SIZE 256
 
 #define forever for(;;)
 
 
 #define forever for(;;)
 
@@ -70,26 +72,26 @@ static char myname[MAXHOSTNAMELEN + 1] = {0};
 static int name_change_token = -1;
 
 static OSSpinLock count_lock = 0;
 static int name_change_token = -1;
 
 static OSSpinLock count_lock = 0;
-static int aslmanager_triggered = 0;
-
 
 #if !TARGET_OS_EMBEDDED
 static vproc_transaction_t vproc_trans = {0};
 
 #if !TARGET_OS_EMBEDDED
 static vproc_transaction_t vproc_trans = {0};
-#define DEFAULT_WORK_QUEUE_SIZE_MAX 10240000
-#else
-#define DEFAULT_WORK_QUEUE_SIZE_MAX 4096000
 #endif
 
 #endif
 
+#define DEFAULT_MEMORY_MAX SYSLOGD_WORK_QUEUE_MEMORY
+
 #define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit  -  remaining messages this second discarded ***"
 
 #define DEFAULT_DB_FILE_MAX 25600000
 #define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit  -  remaining messages this second discarded ***"
 
 #define DEFAULT_DB_FILE_MAX 25600000
-#define DEFAULT_DB_MEMORY_MAX 512
-#define DEFAULT_DB_MEMORY_STR_MAX 4096000
+#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_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
+
+#define ASL_STATS_LEVEL 5
 
 static time_t quota_time = 0;
 static int32_t kern_quota;
 
 static time_t quota_time = 0;
 static int32_t kern_quota;
@@ -107,7 +109,115 @@ static const char *kern_notify_key[] =
        "com.apple.system.log.kernel.debug"
 };
 
        "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 stats_table_t *
+stats_table_new()
+{
+       stats_table_t *t = (stats_table_t *)malloc(sizeof(stats_table_t));
+       if (t == NULL) return NULL;
+
+       t->bucket_count = STATS_TABLE_SIZE;
+       t->bucket = (sender_stats_t **)calloc(t->bucket_count, sizeof(sender_stats_t *));
+       if (t->bucket == NULL)
+       {
+               free(t);
+               return NULL;
+       }
+
+       t->mcount = 0;
+       t->shim_count = 0;
+
+       return t;
+}
+
+static asl_msg_t *
+stats_table_final(stats_table_t *t)
+{
+       uint32_t i;
+       asl_msg_t *msg;
+       char val[64];
+
+       if (t == NULL) return 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)
+               {
+                       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;
+               }
+       }
+
+       free(t->bucket);
+       free(t);
+
+       return msg;
+}
+
+static void
+stats_table_update(stats_table_t *t, const char *sender, uint64_t msg_size)
+{
+       uint32_t i;
+       sender_stats_t *s;
+       uint8_t *p;
+
+       if (t == NULL) return;
+       if (sender == NULL) return;
+
+       /* hash */
+       i = 0;
+       for (p = (uint8_t *)sender; *p != '\0'; p++) i = (i << 1) ^ (i ^ *p);
+       i %= STATS_TABLE_SIZE;
+
+       for (s = t->bucket[i]; s != NULL; s = s->next)
+       {
+               if ((s->sender != NULL) && (strcmp(sender, s->sender) == 0))
+               {
+                       s->count++;
+                       s->size += msg_size;
+                       return;
+               }
+       }
+
+       s = (sender_stats_t *)malloc(sizeof(sender_stats_t));
+       s->sender = strdup(sender);
+       if (s->sender == NULL)
+       {
+               free(s);
+               return;
+       }
+
+       s->count = 1;
+       s->size = msg_size;
+       s->next = t->bucket[i];
+       t->bucket[i] = s;
+}
 
 static uint32_t
 kern_quota_check(time_t now, asl_msg_t *msg, uint32_t level)
 
 static uint32_t
 kern_quota_check(time_t now, asl_msg_t *msg, uint32_t level)
@@ -146,12 +256,42 @@ kern_quota_check(time_t now, asl_msg_t *msg, uint32_t level)
        return VERIFY_STATUS_OK;
 }
 
        return VERIFY_STATUS_OK;
 }
 
+static void
+stats_msg(const char *sender, time_t now, asl_msg_t *msg)
+{
+       asl_msg_t *x;
+       uint64_t msize = 0;
+
+       /* flush stats after N seconds */
+       if ((global.stats_interval != 0) && ((now - global.stats_last) >= global.stats_interval) && (global.stats != NULL))
+       {
+               asl_msg_t *msg = stats_table_final(global.stats);
+               process_message(msg, SOURCE_INTERNAL);
+               global.stats = NULL;
+               global.stats_last = now;
+       }
+
+       if (global.stats == NULL) global.stats = stats_table_new();
+
+       for (x = msg; x != NULL; x = x->next) msize += x->mem_size;
+
+       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);
+}
+
 static const char *
 whatsmyhostname()
 {
        static dispatch_once_t once;
        int check, status;
 
 static const char *
 whatsmyhostname()
 {
        static dispatch_once_t once;
        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);
        dispatch_once(&once, ^{
                snprintf(myname, sizeof(myname), "%s", "localhost");
                notify_register_check(kNotifySCHostNameChange, &name_change_token);
@@ -219,7 +359,7 @@ asl_client_count_decrement()
 static uint32_t
 aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_out)
 {
 static uint32_t
 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;
        char buf[64];
        time_t tick, now;
        uid_t uid;
@@ -244,11 +384,13 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *
        if (val == NULL) asl_msg_set_key_val(msg, ASL_KEY_PID, "0");
        else pid = (pid_t)atoi(val);
 
        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 provided */
+       /* if PID is 1 (launchd), use the RefPID and RefProc provided */
        if (pid == 1)
        {
                val = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PID);
                if (val != NULL) pid = (pid_t)atoi(val);
        if (pid == 1)
        {
                val = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PID);
                if (val != NULL) pid = (pid_t)atoi(val);
+
+               sval = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PROC);
        }
 
        /* Level */
        }
 
        /* Level */
@@ -260,6 +402,7 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *
        snprintf(buf, sizeof(buf), "%d", level);
        asl_msg_set_key_val(msg, ASL_KEY_LEVEL, buf);
 
        snprintf(buf, sizeof(buf), "%d", level);
        asl_msg_set_key_val(msg, ASL_KEY_LEVEL, buf);
 
+
        /* check kernel quota if enabled and no processes are watching */
        if ((pid == 0) && (global.mps_limit > 0) && (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))
        {
@@ -286,7 +429,7 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *
        if ((tick == 0) || (tick > now)) tick = now;
 
        /* Canonical form: seconds since the epoch */
        if ((tick == 0) || (tick > now)) tick = now;
 
        /* Canonical form: seconds since the epoch */
-       snprintf(buf, sizeof(buf) - 1, "%lu", tick);
+       snprintf(buf, sizeof(buf) - 1, "%llu", (unsigned long long) tick);
        asl_msg_set_key_val(msg, ASL_KEY_TIME, buf);
 
        /* Host */
        asl_msg_set_key_val(msg, ASL_KEY_TIME, buf);
 
        /* Host */
@@ -365,19 +508,21 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *
        }
 
        /* Sender */
        }
 
        /* Sender */
-       val = asl_msg_get_val_for_key(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:
                        {
        {
                switch (source)
                {
                        case SOURCE_KERN:
                        {
-                               asl_msg_set_key_val(msg, ASL_KEY_SENDER, "kernel");
+                               sval = "kernel";
+                               asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval);
                                break;
                        }
                        case SOURCE_INTERNAL:
                        {
                                break;
                        }
                        case SOURCE_INTERNAL:
                        {
-                               asl_msg_set_key_val(msg, ASL_KEY_SENDER, "syslogd");
+                               sval = "syslogd";
+                               asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval);
                                break;
                        }
                        default:
                                break;
                        }
                        default:
@@ -386,10 +531,11 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *
                        }
                }
        }
                        }
                }
        }
-       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_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown");
        {
                /* allow UID 0 to send messages with "Sender kernel", but nobody else */
                asl_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown");
+               sval = NULL;
        }
 
        /* Facility */
        }
 
        /* Facility */
@@ -442,14 +588,14 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *
        /* Set DB Expire Time for com.apple.system.utmpx and lastlog */
        if ((!strcmp(fac, "com.apple.system.utmpx")) || (!strcmp(fac, "com.apple.system.lastlog")))
        {
        /* 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);
+               snprintf(buf, sizeof(buf), "%llu", (unsigned long long) tick + global.utmp_ttl);
                asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf);
        }
 
        /* Set DB Expire Time for Filesystem errors */
        if (!strcmp(fac, FSLOG_VAL_FACILITY))
        {
                asl_msg_set_key_val(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);
+               snprintf(buf, sizeof(buf), "%llu", (unsigned long long) tick + FS_TTL_SEC);
                asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf);
        }
 
                asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf);
        }
 
@@ -462,6 +608,11 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *
                disaster_message(msg);
        }
 
                disaster_message(msg);
        }
 
+       /*
+        * gather sender stats
+        */
+       if (source != SOURCE_INTERNAL) stats_msg(sval, now, msg);
+
        return VERIFY_STATUS_OK;
 }
 
        return VERIFY_STATUS_OK;
 }
 
@@ -526,7 +677,8 @@ init_globals(void)
        global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC;
        global.mark_time = DEFAULT_MARK_SEC;
        global.utmp_ttl = DEFAULT_UTMP_TTL_SEC;
        global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC;
        global.mark_time = DEFAULT_MARK_SEC;
        global.utmp_ttl = DEFAULT_UTMP_TTL_SEC;
-       global.max_work_queue_size = DEFAULT_WORK_QUEUE_SIZE_MAX;
+       global.memory_max = DEFAULT_MEMORY_MAX;
+       global.stats_interval = DEFAULT_STATS_INTERVAL;
 
        global.asl_out_module = asl_out_module_init();
        OSSpinLockUnlock(&global.lock);
 
        global.asl_out_module = asl_out_module_init();
        OSSpinLockUnlock(&global.lock);
@@ -603,7 +755,22 @@ control_set_param(const char *s, bool eval)
                return -1;
        }
 
                return -1;
        }
 
-       if (!strcasecmp(l[0], "mark_time"))
+       if (!strcasecmp(l[0], "hostname"))
+       {
+               /* = 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);
        {
                /* = mark_time seconds */
                OSSpinLockLock(&global.lock);
@@ -643,12 +810,20 @@ control_set_param(const char *s, bool eval)
                else global.mps_limit = DEFAULT_MPS_LIMIT;
                OSSpinLockUnlock(&global.lock);
        }
                else global.mps_limit = DEFAULT_MPS_LIMIT;
                OSSpinLockUnlock(&global.lock);
        }
-       else if (!strcasecmp(l[0], "max_work_queue_size"))
+       else if (!strcasecmp(l[0], "memory_max"))
        {
        {
-               /* = max_work_queue_size number */
+               /* = memory_max number */
                OSSpinLockLock(&global.lock);
                OSSpinLockLock(&global.lock);
-               if (eval) global.max_work_queue_size = (int64_t)atoll(l[1]);
-               else global.max_work_queue_size = DEFAULT_WORK_QUEUE_SIZE_MAX;
+               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"))
                OSSpinLockUnlock(&global.lock);
        }
        else if (!strcasecmp(l[0], "max_file_size"))
@@ -752,7 +927,6 @@ void
 process_message(asl_msg_t *msg, uint32_t source)
 {
        int64_t msize = 0;
 process_message(asl_msg_t *msg, uint32_t source)
 {
        int64_t msize = 0;
-       static bool wq_draining = false;
        bool is_control = false;
        asl_msg_t *x;
 
        bool is_control = false;
        asl_msg_t *x;
 
@@ -760,38 +934,24 @@ process_message(asl_msg_t *msg, uint32_t source)
 
        is_control = asl_check_option(msg, ASL_OPT_CONTROL) != 0;
 
 
        is_control = asl_check_option(msg, ASL_OPT_CONTROL) != 0;
 
-       if ((!is_control) && wq_draining)
-       {
-               if (global.work_queue_size >= (global.max_work_queue_size / 2))
-               {
-                       asldebug("Work queue draining: dropped message.\n");
-                       asl_msg_release(msg);
-                       return;
-               }
-               else
-               {
-                       asldebug("Work queue re-enabled at 1/2 max.  size %llu  max %llu\n", global.work_queue_size, global.max_work_queue_size);
-                       wq_draining = false;
-               }
-       }
+       __block vproc_transaction_t vt = vproc_transaction_begin(NULL);
 
        for (x = msg; x != NULL; x = x->next) msize += x->mem_size;
 
 
        for (x = msg; x != NULL; x = x->next) msize += x->mem_size;
 
-       if ((global.work_queue_size + msize) >= global.max_work_queue_size)
+       if ((global.memory_size + msize) >= global.memory_max)
        {
        {
-               char *str = NULL;
-
-               wq_draining = true;
+               char str[256];
                asl_msg_release(msg);
 
                asl_msg_release(msg);
 
-               asldebug("Work queue disabled.  msize %llu  size %llu  max %llu\n", msize, global.work_queue_size + msize, global.max_work_queue_size);
-               asprintf(&str, "[Sender syslogd] [Level 2] [PID %u] [Message Internal work queue size limit exceeded - dropping messages] [UID 0] [UID 0] [Facility syslog]", global.pid);
+               asldebug("Work queue memory limit - dropped message.  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 Received message size %lld overflows work queue limit %lld - dropping message] [UID 0] [UID 0] [Facility syslog]", global.pid, msize, global.memory_max);
                msg = asl_msg_from_string(str);
                msg = asl_msg_from_string(str);
-               free(str);
+               for (x = msg; x != NULL; x = x->next) msize += x->mem_size;
        }
 
        }
 
-       OSAtomicAdd64(msize, &global.work_queue_size);
+       OSAtomicAdd64(msize, &global.memory_size);
        OSAtomicIncrement32(&global.work_queue_count);
        OSAtomicIncrement32(&global.work_queue_count);
+
        dispatch_async(global.work_queue, ^{
                int32_t kplevel;
                uint32_t status;
        dispatch_async(global.work_queue, ^{
                int32_t kplevel;
                uint32_t status;
@@ -817,17 +977,21 @@ process_message(asl_msg_t *msg, uint32_t source)
 
                        if ((uid == 0) && is_control) control_message(msg);
 
 
                        if ((uid == 0) && is_control) control_message(msg);
 
-                       /* send message to output modules */
-                       asl_out_message(msg);
-#if !TARGET_IPHONE_SIMULATOR
-                       if (global.bsd_out_enabled) bsd_out_message(msg);
-#endif
+                       /*
+                        * 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);
                }
 
                asl_msg_release(msg);
 
                }
 
                asl_msg_release(msg);
 
-               OSAtomicAdd64(-1ll * msize, &global.work_queue_size);
                OSAtomicDecrement32(&global.work_queue_count);
                OSAtomicDecrement32(&global.work_queue_count);
+               vproc_transaction_end(NULL, vt);
        });
 }
 
        });
 }
 
@@ -846,34 +1010,6 @@ internal_log_message(const char *str)
        return 0;
 }
 
        return 0;
 }
 
-void
-trigger_aslmanager()
-{
-       dispatch_async(dispatch_get_main_queue(), ^{
-               if (aslmanager_triggered == 0)
-               {
-                       aslmanager_triggered = 1;
-
-                       time_t now = time(0);
-                       if ((now - global.aslmanager_last_trigger) >= ASLMANAGER_DELAY)
-                       {
-                               global.aslmanager_last_trigger = now;
-                               asl_trigger_aslmanager();
-                               aslmanager_triggered = 0;
-                       }
-                       else
-                       {
-                               uint64_t delta = ASLMANAGER_DELAY - (now - global.aslmanager_last_trigger);
-                               dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delta * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
-                                       global.aslmanager_last_trigger = time(0);
-                                       asl_trigger_aslmanager();
-                                       aslmanager_triggered = 0;
-                               });
-                       }
-               }
-       });
-}
-
 int
 asldebug(const char *str, ...)
 {
 int
 asldebug(const char *str, ...)
 {
@@ -887,6 +1023,9 @@ asldebug(const char *str, ...)
        if (dfp == NULL) return 0;
 
        va_start(v, 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);
 
        vfprintf(dfp, str, v);
        va_end(v);
 
@@ -1200,7 +1339,7 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se
        /* Time */
        if (when != NULL)
        {
        /* Time */
        if (when != NULL)
        {
-               snprintf(str, sizeof(str), "%lu", when->tv_sec);
+               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_msg_set_key_val(m, ASL_KEY_TIME, str);
 
                snprintf(str, sizeof(str), "%lu", 1000 * (unsigned long int)when->tv_usec);
@@ -1209,7 +1348,7 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se
        else
        {
                now = time(NULL);
        else
        {
                now = time(NULL);
-               snprintf(str, sizeof(str), "%lu", now);
+               snprintf(str, sizeof(str), "%llu", (unsigned long long) now);
                asl_msg_set_key_val(m, ASL_KEY_TIME, str);
        }
 
                asl_msg_set_key_val(m, ASL_KEY_TIME, str);
        }
 
index 93de9f000526ff600bc18778b7132d5c356fd758..106059b17c1d6167efc57baef5ade3bd40dc747b 100644 (file)
@@ -91,8 +91,21 @@ extern const char *_path_syslogd_log;
 
 #define SEC_PER_DAY 86400
 
 
 #define SEC_PER_DAY 86400
 
-/* trigger aslmanager no more often than 300 seconds */
-#define ASLMANAGER_DELAY 300
+typedef struct sender_stats_s
+{
+       char *sender;
+       uint64_t count;
+       uint64_t size;
+       struct sender_stats_s *next;
+} sender_stats_t;
+
+typedef struct
+{
+       uint32_t mcount;
+       uint32_t shim_count;
+       uint32_t bucket_count;
+       sender_stats_t **bucket;
+} stats_table_t;
 
 typedef struct
 {
 
 typedef struct
 {
@@ -118,7 +131,8 @@ struct global_s
        int reset;
        pid_t pid;
        int32_t work_queue_count;
        int reset;
        pid_t pid;
        int32_t work_queue_count;
-       int64_t work_queue_size;
+       /* memory_size must be aligned for OSAtomicAdd64 */
+       __attribute__((aligned(8))) int64_t memory_size;
        int32_t asl_queue_count;
        int32_t bsd_queue_count;
        pthread_mutex_t *db_lock;
        int32_t asl_queue_count;
        int32_t bsd_queue_count;
        pthread_mutex_t *db_lock;
@@ -134,11 +148,13 @@ struct global_s
        int launchd_enabled;
        module_t **module;
        asl_out_module_t *asl_out_module;
        int launchd_enabled;
        module_t **module;
        asl_out_module_t *asl_out_module;
-       time_t aslmanager_last_trigger;
+       time_t stats_last;
+       stats_table_t *stats;
 
        /* parameters below are configurable as command-line args or in /etc/asl.conf */
        int debug;
        char *debug_file;
 
        /* parameters below are configurable as command-line args or in /etc/asl.conf */
        int debug;
        char *debug_file;
+       char *hostname;
        int dbtype;
        uint32_t db_file_max;
        uint32_t db_memory_max;
        int dbtype;
        uint32_t db_file_max;
        uint32_t db_memory_max;
@@ -148,7 +164,8 @@ struct global_s
        uint64_t bsd_max_dup_time;
        uint64_t mark_time;
        time_t utmp_ttl;
        uint64_t bsd_max_dup_time;
        uint64_t mark_time;
        time_t utmp_ttl;
-       int64_t max_work_queue_size;
+       time_t stats_interval;
+       int64_t memory_max;
 };
 
 extern struct global_s global;
 };
 
 extern struct global_s global;
@@ -178,13 +195,11 @@ const char *asl_syslog_faciliy_num_to_name(int num);
 asl_msg_t *asl_input_parse(const char *in, int len, char *rhost, uint32_t source);
 
 void process_message(asl_msg_t *msg, uint32_t source);
 asl_msg_t *asl_input_parse(const char *in, int len, char *rhost, uint32_t source);
 
 void process_message(asl_msg_t *msg, uint32_t source);
-void asl_out_message(asl_msg_t *msg);
-void bsd_out_message(asl_msg_t *msg);
+void asl_out_message(asl_msg_t *msg, int64_t msize);
+void bsd_out_message(asl_msg_t *msg, int64_t msize);
 int control_set_param(const char *s, bool eval);
 int asl_action_control_set_param(const char *s);
 
 int control_set_param(const char *s, bool eval);
 int asl_action_control_set_param(const char *s);
 
-void trigger_aslmanager();
-
 /* notify SPI */
 uint32_t notify_register_plain(const char *name, int *out_token);
 
 /* notify SPI */
 uint32_t notify_register_plain(const char *name, int *out_token);
 
index b5d812fb6df366a9a7b418ad448e7960032d6486..7f829594ea3ad4209e392ded75010de8d1a85edc 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -37,6 +37,7 @@
 #include <sys/errno.h>
 #include <mach/mach.h>
 #include <mach/mach_error.h>
 #include <sys/errno.h>
 #include <mach/mach.h>
 #include <mach/mach_error.h>
+#include <mach/vm_param.h>
 #include <bsm/libbsm.h>
 #include <errno.h>
 #include <netinet/in.h>
 #include <bsm/libbsm.h>
 #include <errno.h>
 #include <netinet/in.h>
@@ -72,6 +73,8 @@
 #define ASL_ENTITLEMENT_UID_KEY "com.apple.asl.access_as_uid"
 #define ASL_ENTITLEMENT_GID_KEY "com.apple.asl.access_as_gid"
 
 #define ASL_ENTITLEMENT_UID_KEY "com.apple.asl.access_as_uid"
 #define ASL_ENTITLEMENT_GID_KEY "com.apple.asl.access_as_gid"
 
+#define PAGE_ROUND_UP(x) ((((x)+PAGE_SIZE-1)/PAGE_SIZE)*PAGE_SIZE)
+
 static dispatch_queue_t asl_server_queue;
 static dispatch_queue_t watch_queue;
 static dispatch_once_t watch_init_once;
 static dispatch_queue_t asl_server_queue;
 static dispatch_queue_t watch_queue;
 static dispatch_once_t watch_init_once;
@@ -143,7 +146,7 @@ db_asl_open(uint32_t dbtype)
                else
                {
                        if (global.db_file_max != 0) asl_store_max_file_size(global.file_db, global.db_file_max);
                else
                {
                        if (global.db_file_max != 0) asl_store_max_file_size(global.file_db, global.db_file_max);
-                       trigger_aslmanager();
+                       asl_trigger_aslmanager();
                }
        }
 
                }
        }
 
@@ -916,14 +919,26 @@ syslogd_state_query(asl_msg_t *q, asl_msg_list_t **res, uid_t uid)
 
        if (all || (0 == asl_msg_lookup(q, "utmp_ttl", NULL, NULL)))
        {
 
        if (all || (0 == asl_msg_lookup(q, "utmp_ttl", NULL, NULL)))
        {
-               snprintf(val, sizeof(val), "%lu", global.utmp_ttl);
+               snprintf(val, sizeof(val), "%llu", (unsigned long long) global.utmp_ttl);
                asl_msg_set_key_val(m, "utmp_ttl", val);
        }
 
                asl_msg_set_key_val(m, "utmp_ttl", val);
        }
 
-       if (all || (0 == asl_msg_lookup(q, "max_work_queue_size", NULL, NULL)))
+       if (all || (0 == asl_msg_lookup(q, "memory_size", NULL, NULL)))
        {
        {
-               snprintf(val, sizeof(val), "%lld", global.max_work_queue_size);
-               asl_msg_set_key_val(m, "max_work_queue_size", val);
+               snprintf(val, sizeof(val), "%lld", global.memory_size);
+               asl_msg_set_key_val(m, "memory_size", val);
+       }
+
+       if (all || (0 == asl_msg_lookup(q, "memory_max", NULL, NULL)))
+       {
+               snprintf(val, sizeof(val), "%lld", global.memory_max);
+               asl_msg_set_key_val(m, "memory_max", val);
+       }
+
+       if (all || (0 == asl_msg_lookup(q, "stats_interval", NULL, NULL)))
+       {
+               snprintf(val, sizeof(val), "%lld", (long long) global.stats_interval);
+               asl_msg_set_key_val(m, "stats_interval", val);
        }
 
        if (all || (0 == asl_msg_lookup(q, "work_queue_count", NULL, NULL)))
        }
 
        if (all || (0 == asl_msg_lookup(q, "work_queue_count", NULL, NULL)))
@@ -1010,22 +1025,132 @@ syslogd_state_query(asl_msg_t *q, asl_msg_list_t **res, uid_t uid)
        return ASL_STATUS_OK;
 }
 
        return ASL_STATUS_OK;
 }
 
+static kern_return_t
+_server_message_processing(asl_request_msg *request)
+{
+       const uint32_t sbits = MACH_SEND_MSG | MACH_SEND_TIMEOUT;;
+       kern_return_t ks;
+       asl_reply_msg *reply = calloc(1, sizeof(asl_reply_msg) + MAX_TRAILER_SIZE);
+       
+       voucher_mach_msg_state_t voucher = voucher_mach_msg_adopt(&(request->head));
+       
+       /* MIG server routine */
+       asl_ipc_server(&(request->head), &(reply->head));
+       
+       if (!(reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
+       {
+               if (reply->reply.Reply__asl_server_message.RetCode == MIG_NO_REPLY)
+               {
+                       reply->head.msgh_remote_port = MACH_PORT_NULL;
+               }
+               else if ((reply->reply.Reply__asl_server_message.RetCode != KERN_SUCCESS) && (request->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
+               {
+                       /* destroy the request - but not the reply port */
+                       request->head.msgh_remote_port = MACH_PORT_NULL;
+                       mach_msg_destroy(&(request->head));
+               }
+       }
+       
+       if (reply->head.msgh_remote_port != MACH_PORT_NULL)
+       {
+               ks = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL);
+               if ((ks == MACH_SEND_INVALID_DEST) || (ks == MACH_SEND_TIMED_OUT))
+               {
+                       /* clean up */
+                       mach_msg_destroy(&(reply->head));
+               }
+               else if (ks == MACH_SEND_INVALID_HEADER)
+               {
+                       /*
+                        * This should never happen, but we can continue running.
+                        */
+                       char str[256];
+                       asldebug("ERROR: mach_msg() send failed with MACH_SEND_INVALID_HEADER 0x%08x\n", ks);
+                       snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_INVALID_HEADER)]", global.pid, ks);
+                       internal_log_message(str);
+                       mach_msg_destroy(&(reply->head));
+               }
+               else if (ks == MACH_SEND_NO_BUFFER)
+               {
+                       /*
+                        * This should never happen, but the kernel can run out of memory.
+                        * We clean up and continue running.
+                        */
+                       char str[256];
+                       asldebug("ERROR: mach_msg() send failed with MACH_SEND_NO_BUFFER 0x%08x\n", ks);
+                       snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_NO_BUFFER)]", global.pid, ks);
+                       internal_log_message(str);
+                       mach_msg_destroy(&(reply->head));
+               }
+               else if (ks != KERN_SUCCESS)
+               {
+                       /*
+                        * Failed to send a reply message.  This should never happen,
+                        * but the best action is to crash.
+                        */
+                       char str[256];
+                       asldebug("FATAL ERROR: mach_msg() send failed with status 0x%08x\n", ks);
+                       snprintf(str, sizeof(str), "[Sender syslogd] [Level 1] [PID %u] [Facility syslog] [Message FATAL ERROR: mach_msg() send failed with status 0x%08x]", global.pid, ks);
+                       internal_log_message(str);
+                       sleep(1);
+                       abort();
+               }
+       }
+       else if (reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
+       {
+               mach_msg_destroy(&reply->head);
+       }
+       
+       voucher_mach_msg_revert(voucher);
+       free(request);
+       free(reply);
+}
+
 /*
  * Receives messages on the "com.apple.system.logger" mach port.
  * Services database search requests.
  * Runs in it's own thread.
 /*
  * Receives messages on the "com.apple.system.logger" mach port.
  * Services database search requests.
  * Runs in it's own thread.
+ *
+ * The logic in this routine got a bit more complex due to (1) increased logging load and (2) 16K page size.
+ * Out-of-line (OOL) memory sent to syslogd from libasl is allocated in pages, so the minimum size of a 
+ * message is one page.  Since this routine can get slammed with messages at a very high rate, and since
+ * the message queue in the kernel is only 5 messages, it is critical that this routine service the port
+ * as fast as possible.  To that end, it needs to do as little processing as possible.
+ * In the version of this code found up to syslog-312, this routine received messages and dispatched them
+ * on the asl_server_queue for further processing.  When pages were only 4K, this was not a problem.  With
+ * 16K pages, it only takes about 650 messages to run syslogd's dirty memoory size up to the point of its
+ * jetsam limit.  Code was added here to track the memory being used in this queue + the work queue that's
+ * used by process_message(), such that messages will get dropped if the queues reach a memory limit.
+ * The actual message data in the VM pages is typically only a few hundred bytes, so holding VM pages in
+ * the queue was a waste, and seriously limited the number of queued messages.
+ *
+ * The solution implemented here is a bit of a hack.  It peeks at the received message header to determine
+ * which MIG routine is being called.  If the call is for _asl_server_message, it calls asl_ipc_server()
+ * on the server thread.  This routes the call through the MIG server code for error checking and so on,
+ * and invokes _asl_server_message() on this thread.  _asl_server_message() has been modified to copy
+ * the message data into malloced memory, vm_deallocate the OOL memory, and then it dispatches the real
+ * work onto the asl_server_queue.
  */
 void
 database_server()
 {
        asl_request_msg *request;
  */
 void
 database_server()
 {
        asl_request_msg *request;
-       uint32_t rqs;
+       uint32_t rqs, asl_server_message_num = 0;
+       size_t i;
        struct timeval now, send_time;
        mach_dead_name_notification_t *deadname;
        const uint32_t rbits = MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | MACH_RCV_VOUCHER;
        struct timeval now, send_time;
        mach_dead_name_notification_t *deadname;
        const uint32_t rbits = MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | MACH_RCV_VOUCHER;
-
        send_time.tv_sec = 0;
        send_time.tv_usec = 0;
        send_time.tv_sec = 0;
        send_time.tv_usec = 0;
+       struct mig_map_s {
+               const char *routine;
+               int num;
+       } migmap[] = { subsystem_to_name_map_asl_ipc };
+
+       for (i = 0; (i < (sizeof(migmap) / sizeof(struct mig_map_s))) && (asl_server_message_num == 0); i++)
+       {
+               if (!strcmp(migmap[i].routine, "_asl_server_message")) asl_server_message_num = migmap[i].num;
+       }
 
        rqs = sizeof(asl_request_msg) + MAX_TRAILER_SIZE;
 
 
        rqs = sizeof(asl_request_msg) + MAX_TRAILER_SIZE;
 
@@ -1071,84 +1196,15 @@ database_server()
                        continue;
                }
 
                        continue;
                }
 
-               dispatch_async(asl_server_queue, ^{
-                       const uint32_t sbits = MACH_SEND_MSG | MACH_SEND_TIMEOUT;;
-                       kern_return_t ks;
-                       asl_reply_msg *reply = calloc(1, sizeof(asl_reply_msg) + MAX_TRAILER_SIZE);
-
-                       voucher_mach_msg_state_t voucher = voucher_mach_msg_adopt(&(request->head));
-
-                       /* MIG server routine */
-                       asl_ipc_server(&(request->head), &(reply->head));
-
-                       if (!(reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
-                       {
-                               if (reply->reply.Reply__asl_server_message.RetCode == MIG_NO_REPLY)
-                               {
-                                       reply->head.msgh_remote_port = MACH_PORT_NULL;
-                               }
-                               else if ((reply->reply.Reply__asl_server_message.RetCode != KERN_SUCCESS) && (request->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
-                               {
-                                       /* destroy the request - but not the reply port */
-                                       request->head.msgh_remote_port = MACH_PORT_NULL;
-                                       mach_msg_destroy(&(request->head));
-                               }
-                       }
-
-                       if (reply->head.msgh_remote_port != MACH_PORT_NULL)
-                       {
-                               ks = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL);
-                               if ((ks == MACH_SEND_INVALID_DEST) || (ks == MACH_SEND_TIMED_OUT))
-                               {
-                                       /* clean up */
-                                       mach_msg_destroy(&(reply->head));
-                               }
-                               else if (ks == MACH_SEND_INVALID_HEADER)
-                               {
-                                       /*
-                                        * This should never happen, but we can continue running.
-                                        */
-                                       char str[256];
-                                       asldebug("ERROR: mach_msg() send failed with MACH_SEND_INVALID_HEADER 0x%08x\n", ks);
-                                       snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_INVALID_HEADER)]", global.pid, ks);
-                                       internal_log_message(str);
-                                       mach_msg_destroy(&(reply->head));
-                               }
-                               else if (ks == MACH_SEND_NO_BUFFER)
-                               {
-                                       /*
-                                        * This should never happen, but the kernel can run out of memory.
-                                        * We clean up and continue running.
-                                        */
-                                       char str[256];
-                                       asldebug("ERROR: mach_msg() send failed with MACH_SEND_NO_BUFFER 0x%08x\n", ks);
-                                       snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_NO_BUFFER)]", global.pid, ks);
-                                       internal_log_message(str);
-                                       mach_msg_destroy(&(reply->head));
-                               }
-                               else if (ks != KERN_SUCCESS)
-                               {
-                                       /*
-                                        * Failed to send a reply message.  This should never happen,
-                                        * but the best action is to crash.
-                                        */
-                                       char str[256];
-                                       asldebug("FATAL ERROR: mach_msg() send failed with status 0x%08x\n", ks);
-                                       snprintf(str, sizeof(str), "[Sender syslogd] [Level 1] [PID %u] [Facility syslog] [Message FATAL ERROR: mach_msg() send failed with status 0x%08x]", global.pid, ks);
-                                       internal_log_message(str);
-                                       sleep(1);
-                                       abort();
-                               }
-                       }
-                       else if (reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
-                       {
-                               mach_msg_destroy(&reply->head);
-                       }
-
-                       voucher_mach_msg_revert(voucher);
-                       free(request);
-                       free(reply);
-               });
+               int64_t msize = 0;
+               if (request->head.msgh_id == asl_server_message_num)
+               {
+                       _server_message_processing(request);
+               }
+               else
+               {
+                       dispatch_async(asl_server_queue, ^{ _server_message_processing(request); });
+               }
        }
 }
 
        }
 }
 
@@ -1288,7 +1344,7 @@ __asl_server_query_internal
 
        if ((out == NULL) || (outlen == 0)) return KERN_SUCCESS;
 
 
        if ((out == NULL) || (outlen == 0)) return KERN_SUCCESS;
 
-       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, outlen, TRUE);
+       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, outlen, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
        if (kstatus != KERN_SUCCESS)
        {
                free(out);
        if (kstatus != KERN_SUCCESS)
        {
                free(out);
@@ -1420,6 +1476,54 @@ __asl_server_prune
        return KERN_SUCCESS;
 }
 
        return KERN_SUCCESS;
 }
 
+/*
+ * Does the actual processing for __asl_server_message.
+ * Dispatched on asl_server_queue.  This lets us avoid 
+ * calling asl_msg_from_string(), task_name_for_pid(),
+ * and register_session() on the database_server() thread.
+ */
+static void
+_asl_message_processing(char *mbuf, uint64_t msize, uid_t uid, gid_t gid, pid_t pid)
+{
+       asl_msg_t *msg;
+       char tmp[64];
+       kern_return_t kstatus;
+       mach_port_name_t client;
+       
+       msg = asl_msg_from_string(mbuf);
+       free(mbuf);
+
+       /*
+        * process_message() will update global.memory_size with the 
+        * size of msg, and it increements the work_queue_count.
+        */
+       OSAtomicAdd64(-1ll * msize, &global.memory_size);
+       OSAtomicDecrement32(&global.work_queue_count);
+
+       if (msg == NULL) return;
+
+       client = MACH_PORT_NULL;
+       kstatus = task_name_for_pid(mach_task_self(), pid, &client);
+       if (kstatus == KERN_SUCCESS) register_session(client, pid);
+
+       snprintf(tmp, sizeof(tmp), "%d", uid);
+       asl_msg_set_key_val(msg, ASL_KEY_UID, tmp);
+       
+       snprintf(tmp, sizeof(tmp), "%d", gid);
+       asl_msg_set_key_val(msg, ASL_KEY_GID, tmp);
+       
+       snprintf(tmp, sizeof(tmp), "%d", pid);
+       asl_msg_set_key_val(msg, ASL_KEY_PID, tmp);
+       
+       process_message(msg, SOURCE_ASL_MESSAGE);
+}
+
+/*
+ * This MIG server routine is something of a special case in database_server() above.
+ * It is called on the server thread that's responsible for servicing syslogd's mach port.
+ * In this routine we copy the actual ASL message raw string out of the message into
+ * malloc memory, deallocate the message, and dispatch the real work onto the asl_server_queue.
+ */
 kern_return_t
 __asl_server_message
 (
 kern_return_t
 __asl_server_message
 (
@@ -1429,51 +1533,47 @@ __asl_server_message
        audit_token_t token
 )
 {
        audit_token_t token
 )
 {
-       asl_msg_t *msg;
-       char tmp[64];
        uid_t uid;
        gid_t gid;
        pid_t pid;
        uid_t uid;
        gid_t gid;
        pid_t pid;
-       kern_return_t kstatus;
-       mach_port_name_t client;
+       char *mbuf;
 
 
-       if (message == NULL)
+       if (message == NULL) return KERN_SUCCESS;
+
+       if (message[messageCnt - 1] != '\0')
        {
        {
+               vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
                return KERN_SUCCESS;
        }
 
                return KERN_SUCCESS;
        }
 
-       if (message[messageCnt - 1] != '\0')
+       asldebug("__asl_server_message: %s\n", message);
+
+       if ((global.memory_size + messageCnt) > global.memory_max)
        {
        {
+               char str[256];
+               asldebug("Server queue dropped message.  message size %u  queue size %lld  max %lld\n", messageCnt, global.memory_size, global.memory_max);
+               snprintf(str, sizeof(str), "[Sender syslogd] [Level 2] [PID %u] [Message Received message size %u overflows work queue (size %lld limit %lld) - dropping message] [UID 0] [UID 0] [Facility syslog]", global.pid, messageCnt, global.memory_size, global.memory_max);
+               internal_log_message(str);
+               
                vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
                return KERN_SUCCESS;
        }
 
                vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
                return KERN_SUCCESS;
        }
 
-       asldebug("__asl_server_message: %s\n", (message == NULL) ? "NULL" : message);
-
-       msg = asl_msg_from_string(message);
+       mbuf = malloc(messageCnt);
+       if (mbuf != NULL) memcpy(mbuf, message, messageCnt);
        vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
 
        vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
 
-       if (msg == NULL) return KERN_SUCCESS;
+       if (mbuf == NULL) return KERN_SUCCESS;
 
        uid = (uid_t)-1;
        gid = (gid_t)-1;
        pid = (pid_t)-1;
        audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
 
 
        uid = (uid_t)-1;
        gid = (gid_t)-1;
        pid = (pid_t)-1;
        audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
 
-       client = MACH_PORT_NULL;
-       kstatus = task_name_for_pid(mach_task_self(), pid, &client);
-       if (kstatus == KERN_SUCCESS) register_session(client, pid);
+       OSAtomicIncrement32(&global.work_queue_count);
+       OSAtomicAdd64(messageCnt, &(global.memory_size));
 
 
-       snprintf(tmp, sizeof(tmp), "%d", uid);
-       asl_msg_set_key_val(msg, ASL_KEY_UID, tmp);
-
-       snprintf(tmp, sizeof(tmp), "%d", gid);
-       asl_msg_set_key_val(msg, ASL_KEY_GID, tmp);
-
-       snprintf(tmp, sizeof(tmp), "%d", pid);
-       asl_msg_set_key_val(msg, ASL_KEY_PID, tmp);
-
-       process_message(msg, SOURCE_ASL_MESSAGE);
+       dispatch_async(asl_server_queue, ^{ _asl_message_processing(mbuf, messageCnt, uid, gid, pid); });
 
        return KERN_SUCCESS;
 }
 
        return KERN_SUCCESS;
 }
@@ -1574,7 +1674,7 @@ __asl_server_create_aux_link
 
        *newurlCnt = strlen(url) + 1;
 
 
        *newurlCnt = strlen(url) + 1;
 
-       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, *newurlCnt, TRUE);
+       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, *newurlCnt, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
        if (kstatus != KERN_SUCCESS)
        {
                free(url);
        if (kstatus != KERN_SUCCESS)
        {
                free(url);
index a050abadfc42c761c5c0548012db917802be42c0..f8c4cd55372a01ef09c4e6ecfa22e467521777b3 100644 (file)
@@ -619,6 +619,12 @@ session(void *x)
                                                }
                                                else
                                                {
                                                }
                                                else
                                                {
+                                                       free(out);
+                                                       out = NULL;
+
+                                                       asl_msg_list_release(res);
+                                                       res = NULL;
+
                                                        goto exit_session;
                                                }
                                        }
                                                        goto exit_session;
                                                }
                                        }
diff --git a/syslogd.tproj/syslog.conf b/syslogd.tproj/syslog.conf
new file mode 100644 (file)
index 0000000..715162b
--- /dev/null
@@ -0,0 +1,3 @@
+# Note that flat file logs are now configured in /etc/asl.conf
+
+install.*                                              @127.0.0.1:32376
index 6d697697a9c5091feee387dc536ed1a279b8c56d..f5c3f54b5fbcae13141aed8987df5811e536590c 100644 (file)
@@ -447,10 +447,11 @@ int
 main(int argc, const char *argv[])
 {
        int32_t i;
 main(int argc, const char *argv[])
 {
        int32_t i;
+       uint64_t master_val;
 #if !TARGET_IPHONE_SIMULATOR
        int network_change_token;
 #endif
 #if !TARGET_IPHONE_SIMULATOR
        int network_change_token;
 #endif
-       int quota_file_token, asl_db_token;
+       int quota_file_token, asl_db_token, master_token;
        char tstr[32], *notify_key;
        time_t now;
        int first_syslogd_start = 1;
        char tstr[32], *notify_key;
        time_t now;
        int first_syslogd_start = 1;
@@ -650,6 +651,11 @@ main(int argc, const char *argv[])
         */
        write_boot_log(first_syslogd_start);
 
         */
        write_boot_log(first_syslogd_start);
 
+       /* default NOTIFY_SYSTEM_MASTER settings */
+       master_val = 0x0;
+       notify_register_plain(NOTIFY_SYSTEM_MASTER, &master_token);
+       notify_set_state(master_token, master_val);
+
        asldebug("reading launch plist\n");
        launch_config();
 
        asldebug("reading launch plist\n");
        launch_config();
 
index 3f6affd3461e6ad5ed9a5a588ba0e5ad999bcbe9..75557880d5491ef98f786abe5c51568c01731d2d 100644 (file)
@@ -184,7 +184,6 @@ udp_in_init()
        return 0;
 }
 
        return 0;
 }
 
-/* N.B. Does NOT close fds.  They "belong" to launchd. */
 int
 udp_in_close(void)
 {
 int
 udp_in_close(void)
 {
@@ -203,6 +202,7 @@ udp_in_close(void)
 
                if (ufd[i] != -1)
                {
 
                if (ufd[i] != -1)
                {
+                       close(ufd[i]);
                        ufd[i] = -1;
                }
        }
                        ufd[i] = -1;
                }
        }
index e2d6a7379a0bfea89cc5a1ae249551b6bf648b1f..0e3b4e7f2fdf3c44d5cee10ddba71b45ac94ee3c 100644 (file)
@@ -62,7 +62,7 @@ key val
 .Fl x Ar file Ar expression
 .D1 ""
 .Nm
 .Fl x Ar file Ar expression
 .D1 ""
 .Nm
-.Fl c Ar process Op filter
+.Fl c Ar process Op mask
 .D1 ""
 .Nm 
 .Fl config Op options
 .D1 ""
 .Nm 
 .Fl config Op options
@@ -717,15 +717,15 @@ time sending messages that are in most cases unnecessary.
 The
 .Fl c
 option may be used to control filtering.
 The
 .Fl c
 option may be used to control filtering.
-In addition to the internal filter value that processes may set as described above,
+In addition to the internal filter mask value that processes may set as described above,
 the system maintains a global 
 .Dq master
 the system maintains a global 
 .Dq master
-filter.
+filter mask.
 This filter is normally 
 .Dq off , 
 meaning that it has no effect.
 This filter is normally 
 .Dq off , 
 meaning that it has no effect.
-If a value is set for the master filter, it overrides the local filter for all processes. 
-Root user access is required to set the master filter value.
+If a value is set for the master filter mask, it overrides the local filter mask for all processes.
+Root user access is required to set the master filter mask value.
 .Pp
 The current setting of the master filter mask may be inspected using:
 .Pp
 .Pp
 The current setting of the master filter mask may be inspected using:
 .Pp
@@ -739,11 +739,11 @@ These correspond to the priority levels Emergency (Panic), Alert, Critical, Erro
 The character 
 .Dq x
 may be used for Error, as it is used for sending messages.
 The character 
 .Dq x
 may be used for Error, as it is used for sending messages.
-The master filter may be unset with:
+The master filter mask may be deactivated with:
 .Pp
 .Dl syslog -c 0 off
 .Pp
 .Pp
 .Dl syslog -c 0 off
 .Pp
-Since it is common to use the filter as a 
+Since it is common to use the filter mask as a
 .Dq cutoff
 mechanism, for example to cut off messages with Debug and Info priority,
 a single character from the list above may be specified, preceded by a minus sign.
 .Dq cutoff
 mechanism, for example to cut off messages with Debug and Info priority,
 a single character from the list above may be specified, preceded by a minus sign.
@@ -752,11 +752,11 @@ In this case,
 uses a filter mask starting at level 0 (Emergency)
 .Dq up to
 the given level.
 uses a filter mask starting at level 0 (Emergency)
 .Dq up to
 the given level.
-For example, to set the master filter level to cause all processes to log messages from Emergency up to Debug:
+For example, to set the master filter mask to cause all processes to log messages from Emergency up to Debug:
 .Pp
 .Dl syslog -c 0 -d
 .Pp
 .Pp
 .Dl syslog -c 0 -d
 .Pp
-While the master filter level may be set to control the messages produced by all processes,
+While the master filter mask may be set to control the messages produced by all processes,
 another filter mask may be specified for an individual process. 
 If a per-process filter mask is set, it overrides both the local filter mask and the master filter mask.
 The current setting for a per-process filter mask may be inspected using
 another filter mask may be specified for an individual process. 
 If a per-process filter mask is set, it overrides both the local filter mask and the master filter mask.
 The current setting for a per-process filter mask may be inspected using
index 1cfb675b14e53aab7e690c6aef3596b90186d0f7..26629035584a67271f26331249b0c29fb73ee32a 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -136,15 +136,27 @@ static uint32_t dbselect = DB_SELECT_SYSLOGD;
 static uint32_t dbselect = DB_SELECT_ASL;
 #endif
 
 static uint32_t dbselect = DB_SELECT_ASL;
 #endif
 
+typedef struct
+{
+       char *name;
+       uint32_t count;
+       uint32_t total_messages;
+       size_t total_size;
+       uint32_t *messages;
+       size_t *size;
+} sender_stat_t;
+
+#define ASL_IOS_STATS_DIR "/var/log/asl/Logs/ASLStatistics"
+static uint32_t stats_sender_count;
+static sender_stat_t **stats_sender;
+static uint32_t stats_total_all_messages;
+
 /* notify SPI */
 uint32_t notify_register_plain(const char *name, int *out_token);
 
 /* notify SPI */
 uint32_t notify_register_plain(const char *name, int *out_token);
 
-//extern asl_msg_t *asl_msg_from_string(const char *buf);
-//extern char *asl_list_to_string(asl_msg_list_t *list, uint32_t *outlen);
-//extern asl_msg_list_t *asl_list_from_string(const char *buf);
-//extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
 asl_msg_t *_asl_server_control_query(void);
 extern time_t asl_parse_time(const char *in);
 asl_msg_t *_asl_server_control_query(void);
 extern time_t asl_parse_time(const char *in);
+asl_msg_t * asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr);
 /* END PRIVATE API */
 
 static mach_port_t asl_server_port = MACH_PORT_NULL;
 /* END PRIVATE API */
 
 static mach_port_t asl_server_port = MACH_PORT_NULL;
@@ -155,79 +167,129 @@ static const char *myname = "syslog";
 asl_msg_list_t *syslogd_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *last);
 static void printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags);
 
 asl_msg_list_t *syslogd_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *last);
 static void printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags);
 
+#define HELP_UNAVAILABLE -1
+#define HELP_CONTROL HELP_UNAVAILABLE /* undocumented */
+#define HELP_ALL 0
+#define HELP_SEND 1
+#define HELP_REMOTE_CONTROL 2
+#define HELP_CONFIG 3
+#define HELP_MODULE 4
+#define HELP_SEARCH 5
+#define HELP_STATS 6
+
 void
 void
-usage()
+usage(uint32_t section)
 {
 {
+       if (section == HELP_UNAVAILABLE)
+       {
+               fprintf(stderr, "help is not available for this command\n");
+               return;
+       }
+
        fprintf(stderr, "usage:\n");
        fprintf(stderr, "usage:\n");
-       fprintf(stderr, "%s -s [-r host] [-l level] message...\n", myname);
-       fprintf(stderr, "   send a message\n");
-       fprintf(stderr, "\n");
-       fprintf(stderr, "%s -s [-r host] -k key val [key val]...\n", myname);
-       fprintf(stderr, "   send a message with the given keys and values\n");
-       fprintf(stderr, "\n");
-       fprintf(stderr, "%s -c process [filter]\n", myname);
-       fprintf(stderr, "   get (set if filter is specified) syslog filter for process (pid or name)\n");
-       fprintf(stderr, "   level may be any combination of the characters \"p a c e w n i d\"\n");
-       fprintf(stderr, "   p = Emergency (\"Panic\")\n");
-       fprintf(stderr, "   a = Alert\n");
-       fprintf(stderr, "   c = Critical\n");
-       fprintf(stderr, "   e = Error\n");
-       fprintf(stderr, "   w = Warning\n");
-       fprintf(stderr, "   n = Notice\n");
-       fprintf(stderr, "   i = Info\n");
-       fprintf(stderr, "   d = Debug\n");
-       fprintf(stderr, "   a minus sign preceding a single letter means \"up to\" that level\n");
-       fprintf(stderr, "\n");
-       fprintf(stderr, "%s -config [params...]\n", myname);
-       fprintf(stderr, "   without params, fetch and print syslogd parameters and statistics\n");
-       fprintf(stderr, "   otherwise, set or reset syslogd configuration parameters\n");
-       fprintf(stderr, "\n");
-       fprintf(stderr, "%s -module [name [action]]\n", myname);
-       fprintf(stderr, "   with no name, prints configuration for all ASL output modules\n");
-       fprintf(stderr, "   with name and no action, prints configuration for named ASL output module\n");
-       fprintf(stderr, "   supported actions - module name required, use '*' (with single quotes) for all modules:\n");
-       fprintf(stderr, "       enable [01]          enables (or disables with 0) named module\n");
-       fprintf(stderr, "                            does not apply to com.apple.asl when '*' is used\n");
-       fprintf(stderr, "       checkpoint [file]    checkpoints all files or specified file for named module\n");
-       fprintf(stderr, "\n");
-       fprintf(stderr, "%s [-f file...] [-d path...] [-x file] [-w [N]] [-F format] [-nocompress] [-u] [-sort key1 [key2]] [-nsort key1 [key2]] [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname);
-       fprintf(stderr, "   -f     read named file[s], rather than standard log message store.\n");
-       fprintf(stderr, "   -d     read all file in named directory path, rather than standard log message store.\n");
-       fprintf(stderr, "   -x     export to named ASL format file, rather than printing\n");
-       fprintf(stderr, "   -w     watch data store (^C to quit)\n");
-       fprintf(stderr, "          prints the last N matching lines (default 10) before waiting\n");
-       fprintf(stderr, "          \"-w all\" prints all matching lines before waiting\n");
-       fprintf(stderr, "          \"-w boot\" prints all matching lines since last system boot before waiting\n");
-       fprintf(stderr, "   -F     output format may be \"std\", \"raw\", \"bsd\", or \"xml\"\n");
-       fprintf(stderr, "          format may also be a string containing variables of the form\n");
-       fprintf(stderr, "          $Key or $(Key) - use the latter for non-whitespace delimited variables\n");
-       fprintf(stderr, "   -T     timestamp format may be \"sec\" (seconds), \"utc\" (UTC), or \"local\" (local timezone)\n");
-       fprintf(stderr, "   -E     text encoding may be \"vis\", \"safe\", or \"none\"\n");
-       fprintf(stderr, "   -nodc  no duplicate message compression\n");
-       fprintf(stderr, "   -u     print timestamps using UTC (equivalent to \"-T utc\")\n");
-       fprintf(stderr, "   -sort  sort messages using value for specified key1 (secondary sort by key2 if provided)\n");
-       fprintf(stderr, "   -nsort numeric sort messages using value for specified key1 (secondary sort by key2 if provided)\n");
-       fprintf(stderr, "   -k     key/value match\n");
-       fprintf(stderr, "          if no operator or value is given, checks for the existence of the key\n");
-       fprintf(stderr, "          if no operator is given, default is \"%s\"\n", OP_EQ);
-       fprintf(stderr, "   -B     only process log messages since last system boot\n");
-       fprintf(stderr, "   -C     alias for \"-k Facility com.apple.console\"\n");
-       fprintf(stderr, "   -o     begins a new query\n");
-       fprintf(stderr, "          queries are \'OR\'ed together\n");
-       fprintf(stderr, "operators are zero or more modifiers followed by a comparison\n");
-       fprintf(stderr, "   %s   equal\n", OP_EQ);
-       fprintf(stderr, "   %s   not equal\n", OP_NE);
-       fprintf(stderr, "   %s   greater than\n", OP_GT);
-       fprintf(stderr, "   %s   greater or equal\n", OP_GE);
-       fprintf(stderr, "   %s   less than\n", OP_LT);
-       fprintf(stderr, "   %s   less or equal\n", OP_LE);
-       fprintf(stderr, "optional modifiers for operators\n");
-       fprintf(stderr, "   %c    case-fold\n", MOD_CASE_FOLD);
-       fprintf(stderr, "   %c    regular expression\n", MOD_REGEX);
-       fprintf(stderr, "   %c    substring\n", MOD_SUBSTRING);
-       fprintf(stderr, "   %c    prefix\n", MOD_PREFIX);
-       fprintf(stderr, "   %c    suffix\n", MOD_SUFFIX);
-       fprintf(stderr, "   %c    numeric comparison\n", MOD_NUMERIC);
+
+       if ((section == HELP_ALL) || (section == HELP_SEND))
+       {
+               fprintf(stderr, "%s -s [-r host] [-l level] message...\n", myname);
+               fprintf(stderr, "   send a message\n");
+               fprintf(stderr, "\n");
+
+               fprintf(stderr, "%s -s [-r host] -k key val [key val]...\n", myname);
+               fprintf(stderr, "   send a message with the given keys and values\n");
+               fprintf(stderr, "\n");
+       }
+
+       if ((section == HELP_ALL) || (section == HELP_REMOTE_CONTROL))
+       {
+               fprintf(stderr, "%s -c process [mask] [-s [on|off]] [-t [on|off]]\n", myname);
+               fprintf(stderr, "   get (set if mask or actions are specified) syslog filter mask and actions for process (pid or name)\n");
+               fprintf(stderr, "   mask may be any combination of the characters \"p a c e w n i d\"\n");
+               fprintf(stderr, "   p = Emergency (\"Panic\")\n");
+               fprintf(stderr, "   a = Alert\n");
+               fprintf(stderr, "   c = Critical\n");
+               fprintf(stderr, "   e = Error\n");
+               fprintf(stderr, "   w = Warning\n");
+               fprintf(stderr, "   n = Notice\n");
+               fprintf(stderr, "   i = Info\n");
+               fprintf(stderr, "   d = Debug\n");
+               fprintf(stderr, "   a minus sign preceding a single letter means \"up to\" that level\n");
+               fprintf(stderr, "   use \"0\" for process to get or set master syslog flags\n");
+               fprintf(stderr, "   use \"-c process off\" to deactivate current settings\n");
+               fprintf(stderr, "   -s controls sending ASL mesages (to syslogd)\n");
+               fprintf(stderr, "   -t controls sending Activity Tracing mesages\n");
+               fprintf(stderr, "\n");
+       }
+
+       if ((section == HELP_ALL) || (section == HELP_CONFIG))
+       {
+               fprintf(stderr, "%s -config [params...]\n", myname);
+               fprintf(stderr, "   without params, fetch and print syslogd parameters and statistics\n");
+               fprintf(stderr, "   otherwise, set or reset syslogd configuration parameters\n");
+               fprintf(stderr, "\n");
+       }
+
+       if ((section == HELP_ALL) || (section == HELP_MODULE))
+       {
+               fprintf(stderr, "%s -module [name [action]]\n", myname);
+               fprintf(stderr, "   with no name, prints configuration for all ASL output modules\n");
+               fprintf(stderr, "   with name and no action, prints configuration for named ASL output module\n");
+               fprintf(stderr, "   supported actions - module name required, use '*' (with single quotes) for all modules:\n");
+               fprintf(stderr, "       enable [01]          enables (or disables with 0) named module\n");
+               fprintf(stderr, "                            does not apply to com.apple.asl when '*' is used\n");
+               fprintf(stderr, "       checkpoint [file]    checkpoints all files or specified file for named module\n");
+               fprintf(stderr, "\n");
+       }
+
+       if ((section == HELP_ALL) || (section == HELP_SEARCH))
+       {
+               fprintf(stderr, "%s [-f file...] [-d path...] [-x file] [-w [N]] [-F format] [-nocompress] [-u] [-sort key1 [key2]] [-nsort key1 [key2]] [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname);
+               fprintf(stderr, "   -f     read named file[s], rather than standard log message store.\n");
+               fprintf(stderr, "   -d     read all file in named directory path, rather than standard log message store.\n");
+               fprintf(stderr, "   -x     export to named ASL format file, rather than printing\n");
+               fprintf(stderr, "   -w     watch data store (^C to quit)\n");
+               fprintf(stderr, "          prints the last N matching lines (default 10) before waiting\n");
+               fprintf(stderr, "          \"-w all\" prints all matching lines before waiting\n");
+               fprintf(stderr, "          \"-w boot\" prints all matching lines since last system boot before waiting\n");
+               fprintf(stderr, "   -F     output format may be \"std\", \"raw\", \"bsd\", or \"xml\"\n");
+               fprintf(stderr, "          format may also be a string containing variables of the form\n");
+               fprintf(stderr, "          $Key or $(Key) - use the latter for non-whitespace delimited variables\n");
+               fprintf(stderr, "   -T     timestamp format may be \"sec\" (seconds), \"utc\" (UTC), or \"local\" (local timezone)\n");
+               fprintf(stderr, "   -E     text encoding may be \"vis\", \"safe\", or \"none\"\n");
+               fprintf(stderr, "   -nodc  no duplicate message compression\n");
+               fprintf(stderr, "   -u     print timestamps using UTC (equivalent to \"-T utc\")\n");
+               fprintf(stderr, "   -sort  sort messages using value for specified key1 (secondary sort by key2 if provided)\n");
+               fprintf(stderr, "   -nsort numeric sort messages using value for specified key1 (secondary sort by key2 if provided)\n");
+               fprintf(stderr, "   -k     key/value match\n");
+               fprintf(stderr, "          if no operator or value is given, checks for the existence of the key\n");
+               fprintf(stderr, "          if no operator is given, default is \"%s\"\n", OP_EQ);
+               fprintf(stderr, "   -B     only process log messages since last system boot\n");
+               fprintf(stderr, "   -C     alias for \"-k Facility com.apple.console\"\n");
+               fprintf(stderr, "   -o     begins a new query\n");
+               fprintf(stderr, "          queries are \'OR\'ed together\n");
+               fprintf(stderr, "operators are zero or more modifiers followed by a comparison\n");
+               fprintf(stderr, "   %s   equal\n", OP_EQ);
+               fprintf(stderr, "   %s   not equal\n", OP_NE);
+               fprintf(stderr, "   %s   greater than\n", OP_GT);
+               fprintf(stderr, "   %s   greater or equal\n", OP_GE);
+               fprintf(stderr, "   %s   less than\n", OP_LT);
+               fprintf(stderr, "   %s   less or equal\n", OP_LE);
+               fprintf(stderr, "optional modifiers for operators\n");
+               fprintf(stderr, "   %c    case-fold\n", MOD_CASE_FOLD);
+               fprintf(stderr, "   %c    regular expression\n", MOD_REGEX);
+               fprintf(stderr, "   %c    substring\n", MOD_SUBSTRING);
+               fprintf(stderr, "   %c    prefix\n", MOD_PREFIX);
+               fprintf(stderr, "   %c    suffix\n", MOD_SUFFIX);
+               fprintf(stderr, "   %c    numeric comparison\n", MOD_NUMERIC);
+       }
+
+       if ((section == HELP_ALL) || (section == HELP_STATS))
+       {
+               fprintf(stderr, "%s -stats [-n n] [-d path] [-v]\n", myname);
+               fprintf(stderr, "   compiles and prints syslogd usage statistics\n");
+               fprintf(stderr, "   -n n     prints stats for just the top n (e.g. top 10) senders\n");
+               fprintf(stderr, "   -d path  reads the ASL database at the given path for statistics\n");
+               fprintf(stderr, "   -v       verbose ([message_count total_data data_average] for 10 minute intervals)\n");
+       }
 }
 
 const char *
 }
 
 const char *
@@ -259,6 +321,16 @@ module_control(int argc, char *argv[])
        const char *val = NULL;
        uint64_t last;
        char *str;
        const char *val = NULL;
        uint64_t last;
        char *str;
+       int i;
+
+       for (i = 2; i < argc; i++)
+       {
+               if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+               {
+                       usage(HELP_MODULE);
+                       return 0;
+               }
+       }
 
        asl_msg_t *ctl = _asl_server_control_query();
        if (ctl == NULL)
 
        asl_msg_t *ctl = _asl_server_control_query();
        if (ctl == NULL)
@@ -389,10 +461,10 @@ module_control(int argc, char *argv[])
                        fprintf(stderr, "can't allocate memory - exiting\n");
                        exit(-1);
                }
                        fprintf(stderr, "can't allocate memory - exiting\n");
                        exit(-1);
                }
-               
+
                asl_msg_list_append(q, qm);
                asl_msg_release(qm);
                asl_msg_list_append(q, qm);
                asl_msg_release(qm);
-               
+
                asl_msg_set_key_val_op(qm, ASL_KEY_OPTION, "control", ASL_QUERY_OP_EQUAL);
                asprintf(&str, "%s checkpoint%s%s", argv[0], (argc > 2) ? " " : "", (argc > 2) ? argv[2] : "");
                asl_msg_set_key_val_op(qm, "action", str, ASL_QUERY_OP_EQUAL);
                asl_msg_set_key_val_op(qm, ASL_KEY_OPTION, "control", ASL_QUERY_OP_EQUAL);
                asprintf(&str, "%s checkpoint%s%s", argv[0], (argc > 2) ? " " : "", (argc > 2) ? argv[2] : "");
                asl_msg_set_key_val_op(qm, "action", str, ASL_QUERY_OP_EQUAL);
@@ -512,7 +584,7 @@ rcontrol_get_string(const char *name, int *val)
 }
 
 int
 }
 
 int
-rcontrol_set_string(const char *name, int filter)
+rcontrol_set_string(const char *name, uint32_t bits)
 {
        int t, status;
        uint64_t x;
 {
        int t, status;
        uint64_t x;
@@ -520,7 +592,7 @@ rcontrol_set_string(const char *name, int filter)
        status = notify_register_plain(name, &t);
        if (status != NOTIFY_STATUS_OK) return status;
 
        status = notify_register_plain(name, &t);
        if (status != NOTIFY_STATUS_OK) return status;
 
-       x = filter;
+       x = bits;
        status = notify_set_state(t, x);
        notify_post(NOTIFY_RC);
        notify_cancel(t);
        status = notify_set_state(t, x);
        notify_post(NOTIFY_RC);
        notify_cancel(t);
@@ -688,6 +760,18 @@ rcontrol_name(pid_t pid, uid_t uid)
        return str;
 }
 
        return str;
 }
 
+void
+print_eval_bits(uint32_t eval)
+{
+       printf("0x%08x O%s ", eval, (eval & EVAL_ACTIVE) ? "N " : "FF");
+       if (eval & EVAL_SEND_ASL) printf("ASL ");
+       if (eval & EVAL_SEND_TRACE) printf("TRACE ");
+       if (eval & EVAL_TEXT_FILE) printf("TEXT ");
+       if (eval & EVAL_ASL_FILE) printf("FILE ");
+       if (eval & EVAL_TUNNEL) printf("TUNNEL ");
+       printf("/ 0x%02x %s\n", eval & EVAL_LEVEL_MASK, asl_filter_string(eval & EVAL_LEVEL_MASK));
+}
+
 int
 rcontrol_get(pid_t pid, uid_t uid)
 {
 int
 rcontrol_get(pid_t pid, uid_t uid)
 {
@@ -700,27 +784,29 @@ rcontrol_get(pid_t pid, uid_t uid)
                status = rcontrol_get_string(rcontrol_name(pid, uid), &filter);
                if (status == NOTIFY_STATUS_OK)
                {
                status = rcontrol_get_string(rcontrol_name(pid, uid), &filter);
                if (status == NOTIFY_STATUS_OK)
                {
-                       printf("Master filter mask: %s\n", asl_filter_string(filter));
+                       printf("Master settings: ");
+                       print_eval_bits(filter);
                        return 0;
                }
 
                        return 0;
                }
 
-               printf("Unable to determine master filter mask\n");
+               printf("Unable to determine master settings\n");
                return -1;
        }
 
        status = rcontrol_get_string(rcontrol_name(pid, uid), &filter);
        if (status == NOTIFY_STATUS_OK)
        {
                return -1;
        }
 
        status = rcontrol_get_string(rcontrol_name(pid, uid), &filter);
        if (status == NOTIFY_STATUS_OK)
        {
-               printf("Process %d syslog filter mask: %s\n", pid, asl_filter_string(filter));
+               printf("Process %d syslog settings: ", pid);
+               print_eval_bits(filter);
                return 0;
        }
 
                return 0;
        }
 
-       printf("Unable to determine syslog filter mask for pid %d\n", pid);
+       printf("Unable to determine syslog settings for pid %d\n", pid);
        return -1;
 }
 
 int
        return -1;
 }
 
 int
-rcontrol_set(pid_t pid, uid_t uid, int filter)
+rcontrol_set(pid_t pid, uid_t uid, uint32_t bits)
 {
        int status;
        const char *rcname;
 {
        int status;
        const char *rcname;
@@ -729,7 +815,7 @@ rcontrol_set(pid_t pid, uid_t uid, int filter)
 
        if (pid < 0)
        {
 
        if (pid < 0)
        {
-               status = rcontrol_set_string(rcname, filter);
+               status = rcontrol_set_string(rcname, bits);
 
                if (status == NOTIFY_STATUS_OK)
                {
 
                if (status == NOTIFY_STATUS_OK)
                {
@@ -741,7 +827,7 @@ rcontrol_set(pid_t pid, uid_t uid, int filter)
                return -1;
        }
 
                return -1;
        }
 
-       status = rcontrol_set_string(rcname, filter);
+       status = rcontrol_set_string(rcname, bits);
        if (status == NOTIFY_STATUS_OK)
        {
                status = notify_post(rcname);
        if (status == NOTIFY_STATUS_OK)
        {
                status = notify_post(rcname);
@@ -763,7 +849,7 @@ rsend(asl_msg_t *msg, char *rhost)
        int s;
        struct sockaddr_in dst;
        struct hostent *h;
        int s;
        struct sockaddr_in dst;
        struct hostent *h;
-       char myname[MAXHOSTNAMELEN + 1];
+       char host_name[MAXHOSTNAMELEN + 1];
 
        if (msg == NULL) return 0;
 
 
        if (msg == NULL) return 0;
 
@@ -787,14 +873,14 @@ rsend(asl_msg_t *msg, char *rhost)
 
        tick = time(NULL);
        timestr = NULL;
 
        tick = time(NULL);
        timestr = NULL;
-       asprintf(&timestr, "%lu", tick);
+       asprintf(&timestr, "%llu", (unsigned long long)tick);
        if (timestr != NULL)
        {
                asl_msg_set_key_val(msg, ASL_KEY_TIME, timestr);
                free(timestr);
        }
 
        if (timestr != NULL)
        {
                asl_msg_set_key_val(msg, ASL_KEY_TIME, timestr);
                free(timestr);
        }
 
-       if (gethostname(myname, MAXHOSTNAMELEN) == 0) asl_msg_set_key_val(msg, ASL_KEY_HOST, myname);
+       if (gethostname(host_name, MAXHOSTNAMELEN) == 0) asl_msg_set_key_val(msg, ASL_KEY_HOST, host_name);
 
        len = 0;
        str = asl_msg_to_string((asl_msg_t *)msg, &len);
 
        len = 0;
        str = asl_msg_to_string((asl_msg_t *)msg, &len);
@@ -821,7 +907,7 @@ rlegacy(char *msg, int level, char *rhost)
        int s;
        struct sockaddr_in dst;
        struct hostent *h;
        int s;
        struct sockaddr_in dst;
        struct hostent *h;
-       char myname[MAXHOSTNAMELEN + 1];
+       char host_name[MAXHOSTNAMELEN + 1];
 
        if (msg == NULL) return 0;
 
 
        if (msg == NULL) return 0;
 
@@ -841,9 +927,9 @@ rlegacy(char *msg, int level, char *rhost)
        ltime = ctime(&tick);
        ltime[19] = '\0';
 
        ltime = ctime(&tick);
        ltime[19] = '\0';
 
-       gethostname(myname, MAXHOSTNAMELEN);
+       gethostname(host_name, MAXHOSTNAMELEN);
 
 
-       asprintf(&out, "<%d>%s %s syslog[%d]: %s", level, ltime+4, myname, getpid(), msg);
+       asprintf(&out, "<%d>%s %s syslog[%d]: %s", level, ltime+4, host_name, getpid(), msg);
        len = strlen(out);
        sendto(s, out, len, 0, (const struct sockaddr *)&dst, sizeof(struct sockaddr_in));
 
        len = strlen(out);
        sendto(s, out, len, 0, (const struct sockaddr *)&dst, sizeof(struct sockaddr_in));
 
@@ -852,6 +938,230 @@ rlegacy(char *msg, int level, char *rhost)
        return 0;
 }
 
        return 0;
 }
 
+void
+stats_print_sender_stats(sender_stat_t *s, uint32_t interval, bool print_samples)
+{
+       uint32_t i;
+       uint32_t p10000 = (s->total_messages * 10000) / stats_total_all_messages;
+
+       if (strcmp(s->name, "*")) printf("%s: %u (%u.%02u%%) %lu\n", s->name, s->total_messages, p10000 / 100, p10000 % 100, s->total_size);
+       else printf("TOTAL: %u (100.00%%) %lu\n", s->total_messages, s->total_size);
+
+       if (print_samples)
+       {
+               int k = 0;
+               printf("[message_count data_size data_average]\n");
+
+               for (i = 0, k = 0; i < s->count; i++)
+               {
+                       size_t avg = 0;
+
+                       if (s->messages[i] > 0) avg = s->size[i] / s->messages[i];
+                       printf("[%u %lu %lu]", s->messages[i], s->size[i], avg);
+                       if (++k == 6)
+                       {
+                               printf("\n");
+                               k = 0;
+                       }
+                       else
+                       {
+                               printf(" ");
+                       }
+               }
+
+               for (; i < interval; i++)
+               {
+                       printf("[0 0 0]");
+                       if ((++k == 6) || ((i + 1) == interval))
+                       {
+                               printf("\n");
+                               k = 0;
+                       }
+                       else
+                       {
+                               printf(" ");
+                       }
+               }
+
+               printf("\n");
+       }
+}
+
+int
+stats_n_comp(const void *x, const void *y)
+{
+       int pn, qn;
+       sender_stat_t **p = (sender_stat_t **)x;
+       sender_stat_t **q = (sender_stat_t **)y;
+       pn = (*p)->total_messages;
+       qn = (*q)->total_messages;
+       return qn - pn;
+}
+
+void
+stats_sender_set_stat_numbers(const char *name, sender_stat_t *s, uint32_t interval, uint32_t nmsgs, size_t msize)
+{
+       s->messages = (uint32_t *)reallocf(s->messages, interval * sizeof(uint32_t));
+       s->size = (size_t *)reallocf(s->size, interval * sizeof(size_t));
+
+       for (; s->count < interval; s->count++)
+       {
+               s->messages[s->count] = 0;
+               s->size[s->count] = 0;
+       }
+
+       s->messages[interval - 1] = nmsgs;
+       s->size[interval - 1] = msize;
+
+       s->total_messages += nmsgs;
+       s->total_size += msize;
+
+       if (strcmp(name, "*")) stats_total_all_messages += nmsgs;
+}
+
+void
+stats_sender_set_stats(uint32_t interval, const char *name, uint32_t nmsgs, size_t msize)
+{
+       uint32_t i;
+       for (i = 0; i < stats_sender_count; i++)
+       {
+               if (strcmp(stats_sender[i]->name, name) == 0)
+               {
+                       stats_sender_set_stat_numbers(name, stats_sender[i], interval, nmsgs, msize);
+                       return;
+               }
+       }
+
+       stats_sender = (sender_stat_t **)realloc(stats_sender, (stats_sender_count + 1) * sizeof(sender_stat_t *));
+       stats_sender[stats_sender_count] = (sender_stat_t *)calloc(1, sizeof(sender_stat_t));
+       stats_sender[stats_sender_count]->name = strdup(name);
+
+       stats_sender_set_stat_numbers(name, stats_sender[stats_sender_count], interval, nmsgs, msize);
+       stats_sender_count++;
+}
+
+void
+stats_process_stat_msg(uint32_t interval, asl_object_t msg)
+{
+       uint32_t i, n;
+
+       n = asl_count(msg);
+
+       for (i = 0; i < n; i++)
+       {
+               const char *key = NULL;
+               const char *val = NULL;
+               uint32_t s_n = 0;
+               size_t s_size = 0;
+               if (asl_fetch_key_val_op(msg, i, &key, &val, NULL) != 0) break;
+               if (key[0] == '*')
+               {
+                       if (2 == sscanf(val, "%u %lu", &s_n, &s_size))
+                       {
+                               stats_sender_set_stats(interval, key + 1, s_n, s_size);
+                       }
+               }
+       }
+}
+
+
+int
+asl_stats(int argc, char *argv[])
+{
+       asl_object_t msg;
+       uint32_t i, interval, top = UINT32_MAX;
+       bool print_samples = false;
+       asl_object_t store = NULL;
+
+       for (i = 2; i < argc; i++)
+       {
+               if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+               {
+                       usage(HELP_STATS);
+                       return 0;
+               }
+               else if (!strcmp(argv[i], "-n"))
+               {
+                       i++;
+                       if (i >= argc)
+                       {
+                               fprintf(stderr, "error: expected an integer value following \"-n\"\n");
+                               usage(HELP_STATS);
+                               return -1;
+                       }
+
+                       top = 1 + atoi(argv[i]);
+               }
+               else if (!strcmp(argv[i], "-v"))
+               {
+                       print_samples = true;
+               }
+               else if (!strcmp(argv[i], "-d"))
+               {
+                       i++;
+                       if (i >= argc)
+                       {
+                               fprintf(stderr, "error: expected a directory path following \"-d\"\n");
+                               usage(HELP_STATS);
+                               return -1;
+                       }
+                       store = asl_open_path(argv[i], 0);
+                       if (store == NULL)
+                       {
+                               fprintf(stderr, "error: failed to open ASL directory %s\n", argv[i]);
+                               return -1;
+                       }
+               }
+       }
+
+#if TARGET_OS_EMBEDDED
+       if (store == NULL) store = asl_open_path(ASL_IOS_STATS_DIR, 0);
+       if (store == NULL)
+       {
+               fprintf(stderr, "error: failed to open ASL directory %s\n", ASL_IOS_STATS_DIR);
+               return -1;
+       }
+#endif
+
+       asl_object_t stats_query = asl_new(ASL_TYPE_QUERY);
+       if (stats_query == NULL)
+       {
+               fprintf(stderr, "error: failed to create stats_query\n");
+               return -1;
+       }
+
+       asl_set_query(stats_query, ASL_KEY_FACILITY, "com.apple.asl.statistics", ASL_QUERY_OP_EQUAL);
+
+       asl_object_t stats = asl_search(store, stats_query);
+       asl_release(stats_query);
+       asl_release(store);
+
+       if (stats == NULL)
+       {
+               printf("no statistics records in the ASL database\n");
+               return 0;
+       }
+
+       for (interval = 1, msg = asl_next(stats); msg != NULL; interval++, msg = asl_next(stats))
+       {
+               stats_process_stat_msg(interval, msg);
+       }
+
+       asl_release(stats);
+
+       qsort(stats_sender, stats_sender_count, sizeof(sender_stat_t *), stats_n_comp);
+
+       printf("sender: message_count (%% of total) data_size\n");
+
+       for (i = 0; (i < stats_sender_count) && (i < top); i++)
+       {
+               stats_print_sender_stats(stats_sender[i], interval - 1, print_samples);
+       }
+
+       /* NB sender stats are not freed since we exit after this */
+       return 0;
+}
+
 static int
 _isanumber(char *s)
 {
 static int
 _isanumber(char *s)
 {
@@ -917,20 +1227,24 @@ asl_string_to_char_level(const char *s)
 int
 syslog_remote_control(int argc, char *argv[])
 {
 int
 syslog_remote_control(int argc, char *argv[])
 {
-       int pid, uid, status, mask;
+       int i, pid, uid, status, mask;
+       uint32_t bits;
 
 
-       if ((argc < 3) || (argc > 4))
+       if (argc < 3)
        {
        {
-               fprintf(stderr, "usage:\n");
-               fprintf(stderr, "%s -c process [mask]\n", myname);
-               fprintf(stderr, "   get (set if mask is specified) syslog filter mask for process (pid or name)\n");
-               fprintf(stderr, "   process may be pid or process name\n");
-               fprintf(stderr, "   use \"-c 0\" to get master syslog filter mask\n");
-               fprintf(stderr, "   use \"-c 0 off\" to disable master syslog filter mask\n");
-               fprintf(stderr, "\n");
+               usage(HELP_REMOTE_CONTROL);
                return -1;
        }
 
                return -1;
        }
 
+       for (i = 2; i < argc; i++)
+       {
+               if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+               {
+                       usage(HELP_REMOTE_CONTROL);
+                       return 0;
+               }
+       }
+
        pid = RC_MASTER;
        uid = -2;
 
        pid = RC_MASTER;
        uid = -2;
 
@@ -966,36 +1280,78 @@ syslog_remote_control(int argc, char *argv[])
 
        if (pid == 0) pid = RC_MASTER;
 
 
        if (pid == 0) pid = RC_MASTER;
 
-       if (argc == 4)
+       if (argc == 3)
        {
        {
-               if ((pid == RC_MASTER) && (!strcasecmp(argv[3], "off"))) mask = 0;
+               rcontrol_get(pid, uid);
+               return 0;
+       }
+
+       bits = EVAL_ACTIVE | EVAL_SEND_ASL | EVAL_SEND_TRACE;
+
+       for (i = 3; i < argc; i++)
+       {
+               if ((!strcasecmp(argv[i], "off")) || (!strcmp(argv[i], "0")))
+               {
+                       bits = 0;
+               }
+               else if (!strcmp(argv[i], "-s"))
+               {
+                       if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+                       {
+                               i++;
+                               if (!strcasecmp(argv[i], "off") || !strcmp(argv[i], "0")) bits &= ~EVAL_SEND_ASL;
+                       }
+               }
+               else if (!strcmp(argv[i], "-t"))
+               {
+                       if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+                       {
+                               i++;
+                               if (!strcasecmp(argv[i], "off") || !strcmp(argv[i], "0")) bits &= ~EVAL_SEND_TRACE;
+                       }
+               }
                else
                {
                else
                {
-                       mask = asl_string_to_filter(argv[3]);
+                       mask = asl_string_to_filter(argv[i]);
                        if (mask < 0)
                        {
                        if (mask < 0)
                        {
-                               printf("unknown syslog mask: %s\n", argv[3]);
+                               printf("can't understand mask: %s\n", argv[i]);
                                return -1;
                        }
                                return -1;
                        }
+                       bits = (bits & EVAL_ACTION_MASK) | mask;
                }
                }
-
-               rcontrol_set(pid, uid, mask);
-       }
-       else
-       {
-               rcontrol_get(pid, uid);
        }
 
        }
 
+       rcontrol_set(pid, uid, bits);
        return 0;
 }
 
 int
 syslog_send(int argc, char *argv[])
 {
        return 0;
 }
 
 int
 syslog_send(int argc, char *argv[])
 {
-       int i, start, kv, len, rfmt, rlevel;
-       asl_client_t *asl;
+       int status, i, start, kv, len, rfmt, rlevel;
+       asl_object_t asl = NULL;
        asl_msg_t *m;
        char tmp[64], *str, *rhost;
        asl_msg_t *m;
        char tmp[64], *str, *rhost;
+       struct timeval tval = {0, 0};
+       char host_name[MAXHOSTNAMELEN + 1];
+
+       for (i = 2; i < argc; i++)
+       {
+               if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+               {
+                       usage(HELP_SEND);
+                       return 0;
+               }
+       }
+
+       status = gettimeofday(&tval, NULL);
+       if (status != 0)
+       {
+               time_t tick = time(NULL);
+               tval.tv_sec = tick;
+               tval.tv_usec = 0;
+       }
 
        kv = 0;
        rhost = NULL;
 
        kv = 0;
        rhost = NULL;
@@ -1026,16 +1382,42 @@ syslog_send(int argc, char *argv[])
                        }
                        start = i+1;
                }
                        }
                        start = i+1;
                }
+               else if (!strcmp(argv[i], "-x"))
+               {
+                       i++;
+                       if (i >= argc)
+                       {
+                               fprintf(stderr, "expected a path following -x\n");
+                               return -1;
+                       }
+
+                       asl = asl_open_path(argv[i], ASL_OPT_OPEN_WRITE);
+                       if (asl == NULL)
+                       {
+                               fprintf(stderr, "Could not open %s for write\n", argv[i]);
+                               return -1;
+                       }
+               }
        }
 
        }
 
-       asl = asl_client_open(myname, "syslog", 0);
-       asl_client_set_filter(asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
 
 
-       m = asl_msg_new(ASL_TYPE_MSG);
-       asl_msg_set_key_val(m, ASL_KEY_SENDER, myname);
+       if (asl == NULL) asl = asl_open(myname, "syslog", 0);
+       asl_set_filter(asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+
+       m = asl_base_msg(NULL, rlevel, &tval, myname, "syslog", NULL);
+       if (m == NULL)
+       {
+               fprintf(stderr, "Could not create message\n");
+               return -1;
+       }
+
+       if (gethostname(host_name, MAXHOSTNAMELEN) == 0) asl_msg_set_key_val(m, ASL_KEY_HOST, host_name);
 
 
-       sprintf(tmp, "%d", rlevel);
-       asl_msg_set_key_val(m, ASL_KEY_LEVEL, tmp);
+       snprintf(tmp, sizeof(tmp), "%d", getuid());
+       asl_msg_set_key_val(m, ASL_KEY_UID, tmp);
+
+       snprintf(tmp, sizeof(tmp), "%d", getgid());
+       asl_msg_set_key_val(m, ASL_KEY_GID, tmp);
 
        str = NULL;
 
 
        str = NULL;
 
@@ -1065,7 +1447,7 @@ syslog_send(int argc, char *argv[])
 
        if (rhost == NULL)
        {
 
        if (rhost == NULL)
        {
-               asl_client_send(asl, m);
+               asl_send(asl, (asl_object_t)m);
        }
        else if (rfmt == SEND_FORMAT_ASL)
        {
        }
        else if (rfmt == SEND_FORMAT_ASL)
        {
@@ -1080,7 +1462,7 @@ syslog_send(int argc, char *argv[])
 
        if (str != NULL) free(str);
 
 
        if (str != NULL) free(str);
 
-       asl_client_release(asl);
+       asl_release(asl);
 
        return 0;
 }
 
        return 0;
 }
@@ -1096,6 +1478,15 @@ syslog_config(int argc, char *argv[])
        asl_string_t *str;
        const char *key, *val;
 
        asl_string_t *str;
        const char *key, *val;
 
+       for (i = 2; i < argc; i++)
+       {
+               if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+               {
+                       usage(HELP_CONFIG);
+                       return 0;
+               }
+       }
+
        if (argc == 2)
        {
                asl_msg_t *ctl = _asl_server_control_query();
        if (argc == 2)
        {
                asl_msg_t *ctl = _asl_server_control_query();
@@ -1156,6 +1547,15 @@ syslog_control(int argc, char *argv[])
        asl_msg_t *m;
        asl_string_t *str;
 
        asl_msg_t *m;
        asl_string_t *str;
 
+       for (i = 2; i < argc; i++)
+       {
+               if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+               {
+                       usage(HELP_CONTROL);
+                       return 0;
+               }
+       }
+
        uid = geteuid();
        if (uid != 0)
        {
        uid = geteuid();
        if (uid != 0)
        {
@@ -1331,7 +1731,7 @@ syslogd_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *l
        len = 0;
        str = asl_msg_list_to_string(q, &len);
 
        len = 0;
        str = asl_msg_list_to_string(q, &len);
 
-       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
+       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
        if (kstatus != KERN_SUCCESS)
        {
                free(str);
        if (kstatus != KERN_SUCCESS)
        {
                free(str);
@@ -1538,15 +1938,15 @@ sort_compare_key(asl_msg_t *a, asl_msg_t *b, const char *key)
 }
 
 int
 }
 
 int
-sort_compare(const void *ap, const void *bp)
+sort_compare(const void **ap, const void **bp)
 {
        int cmp;
        asl_msg_t *a, *b;
 
        if (sort_key == NULL) return 0;
 
 {
        int cmp;
        asl_msg_t *a, *b;
 
        if (sort_key == NULL) return 0;
 
-       a = (asl_msg_t *)ap;
-       b = (asl_msg_t *)bp;
+       a = (asl_msg_t *)*ap;
+       b = (asl_msg_t *)*bp;
 
        cmp = sort_compare_key(a, b, sort_key);
        if ((cmp == 0) && (sort_key_2 != NULL)) cmp = sort_compare_key(a, b, sort_key_2);
 
        cmp = sort_compare_key(a, b, sort_key);
        if ((cmp == 0) && (sort_key_2 != NULL)) cmp = sort_compare_key(a, b, sort_key_2);
@@ -1921,13 +2321,14 @@ main(int argc, char *argv[])
 
        if (getuid() == 0) iamroot = 1;
 
 
        if (getuid() == 0) iamroot = 1;
 
+       if ((argc > 1) && ((!strcmp(argv[1], "-help")) || (!strcmp(argv[1], "--help"))))
+       {
+               usage(HELP_ALL);
+               exit(0);
+       }
+
        for (i = 1; i < argc; i++)
        {
        for (i = 1; i < argc; i++)
        {
-               if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
-               {
-                       usage();
-                       exit(0);
-               }
 
                if ((!strcmp(argv[i], "-time")) || (!strcmp(argv[i], "--time")))
                {
 
                if ((!strcmp(argv[i], "-time")) || (!strcmp(argv[i], "--time")))
                {
@@ -1936,6 +2337,12 @@ main(int argc, char *argv[])
                        exit(0);
                }
 
                        exit(0);
                }
 
+               if ((!strcmp(argv[i], "-stats")) || (!strcmp(argv[i], "--stats")))
+               {
+                       asl_stats(argc, argv);
+                       exit(0);
+               }
+
                if ((!strcmp(argv[i], "-config")) || (!strcmp(argv[i], "--config")))
                {
                        syslog_config(argc, argv);
                if ((!strcmp(argv[i], "-config")) || (!strcmp(argv[i], "--config")))
                {
                        syslog_config(argc, argv);
@@ -2113,7 +2520,7 @@ main(int argc, char *argv[])
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
-                               usage();
+                               usage(HELP_SEARCH);
                                exit(1);
                        }
 
                                exit(1);
                        }
 
@@ -2126,7 +2533,7 @@ main(int argc, char *argv[])
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
-                               usage();
+                               usage(HELP_SEARCH);
                                exit(1);
                        }
 
                                exit(1);
                        }
 
@@ -2143,7 +2550,7 @@ main(int argc, char *argv[])
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
-                               usage();
+                               usage(HELP_SEARCH);
                                exit(1);
                        }
 
                                exit(1);
                        }
 
@@ -2178,7 +2585,7 @@ main(int argc, char *argv[])
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
-                               usage();
+                               usage(HELP_SEARCH);
                                exit(1);
                        }
 
                                exit(1);
                        }
 
@@ -2240,7 +2647,7 @@ main(int argc, char *argv[])
                                        fprintf(stderr, "invalid sequence: -k");
                                        for (j = i; j <= n; j++) fprintf(stderr, " %s", argv[j]);
                                        fprintf(stderr, "\n");
                                        fprintf(stderr, "invalid sequence: -k");
                                        for (j = i; j <= n; j++) fprintf(stderr, " %s", argv[j]);
                                        fprintf(stderr, "\n");
-                                       usage();
+                                       usage(HELP_SEARCH);
                                        exit(1);
                                }
                        }
                                        exit(1);
                                }
                        }
@@ -2359,22 +2766,22 @@ main(int argc, char *argv[])
                        fprintf(stderr, "\ncan't allocate memory - exiting\n");
                        exit(1);
                }
                        fprintf(stderr, "\ncan't allocate memory - exiting\n");
                        exit(1);
                }
-               
+
                bq = asl_msg_new(ASL_TYPE_QUERY);
                if (bq == NULL)
                {
                        fprintf(stderr, "\ncan't allocate memory - exiting\n");
                        exit(1);
                }
                bq = asl_msg_new(ASL_TYPE_QUERY);
                if (bq == NULL)
                {
                        fprintf(stderr, "\ncan't allocate memory - exiting\n");
                        exit(1);
                }
-               
+
                asl_msg_list_append(bt, bq);
                asl_msg_release(bq);
                asl_msg_list_append(bt, bq);
                asl_msg_release(bq);
-               
+
                asl_msg_set_key_val_op(bq, "ut_type", "2", ASL_QUERY_OP_EQUAL);
                asl_msg_set_key_val_op(bq, "ut_type", "2", ASL_QUERY_OP_EQUAL);
-               
+
                search_once(NULL, NULL, 0, (asl_msg_list_t *)bt, -1, &qmin, 1, 1, -1, 0);
                asl_msg_list_release(bt);
                search_once(NULL, NULL, 0, (asl_msg_list_t *)bt, -1, &qmin, 1, 1, -1, 0);
                asl_msg_list_release(bt);
-               
+
                if (qmin > 0) qmin--;
                tail_count = 0;
        }
                if (qmin > 0) qmin--;
                tail_count = 0;
        }
index fa9af9ed75e1655762459f463fcec1b18b3a9a3d..1c7c2936be51e2efd4c1d32bcd3e0190a9144dda 100644 (file)
@@ -1,3 +1,3 @@
 #include "base.xcconfig"
 
 #include "base.xcconfig"
 
-INSTALL_PATH_ACTUAL = /usr/sbin
+INSTALL_PATH = /usr/sbin
index e3a569e9cd17cbff303f39d1c9cce97e55bd991d..74940e824c72f3bf2134d3d749705637fdb40507 100644 (file)
@@ -1,5 +1 @@
 #include "<DEVELOPER_DIR>/Makefiles/CoreOS/Xcode/BSD.xcconfig"
 #include "<DEVELOPER_DIR>/Makefiles/CoreOS/Xcode/BSD.xcconfig"
-#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/SimulatorSupport.xcconfig"
-
-// Set INSTALL_PATH[sdk=macosx*] when SimulatorSupport.xcconfig is unavailable
-INSTALL_PATH[sdk=macosx*] = $(INSTALL_PATH_ACTUAL)
index c2ea1af6bd3d61d12d8c03d8b4ffc5dbc0579565..82e61226bde6b3260bb5ce90dcd2d0a6e3e18bcd 100644 (file)
@@ -8,19 +8,17 @@ EXECUTABLE_PREFIX = libsystem_
 
 PRODUCT_NAME = asl
 
 
 PRODUCT_NAME = asl
 
-INSTALL_PATH_ACTUAL = /usr/lib/system
+INSTALL_PATH = /usr/lib/system
 
 
-PUBLIC_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/include
-PRIVATE_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/local/include
+PUBLIC_HEADERS_FOLDER_PATH = /usr/include
+PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include
 
 LINK_WITH_STANDARD_LIBRARIES = NO
 
 CR_LDFLAGS = -lCrashReporterClient
 LIBCOMPILER_RT_LDFLAGS = -lcompiler_rt
 LIBCLOSURE_LDFLAGS = -lsystem_blocks
 
 LINK_WITH_STANDARD_LIBRARIES = NO
 
 CR_LDFLAGS = -lCrashReporterClient
 LIBCOMPILER_RT_LDFLAGS = -lcompiler_rt
 LIBCLOSURE_LDFLAGS = -lsystem_blocks
-LIBCLOSURE_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_blocks
 LIBC_LDFLAGS = -lsystem_c
 LIBC_LDFLAGS = -lsystem_c
-LIBC_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_c
 LIBMALLOC_LDFLAGS = -lsystem_malloc
 LIBNOTIFY_LDFLAGS = -lsystem_notify
 LIBPLATFORM_LDFLAGS = -lsystem_platform
 LIBMALLOC_LDFLAGS = -lsystem_malloc
 LIBNOTIFY_LDFLAGS = -lsystem_notify
 LIBPLATFORM_LDFLAGS = -lsystem_platform
@@ -30,14 +28,10 @@ LIBPTHREAD_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_pthread
 LIBSYSCALL_LDFLAGS = -lsystem_kernel
 LIBSYSCALL_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_kernel
 LIBM_LDFLAGS = -lsystem_m
 LIBSYSCALL_LDFLAGS = -lsystem_kernel
 LIBSYSCALL_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_kernel
 LIBM_LDFLAGS = -lsystem_m
-LIBM_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_m
 LIBDYLD_LDFLAGS = -ldyld
 LIBTRACE_LDFLAGS = -lsystem_trace
 LIBDYLD_LDFLAGS = -ldyld
 LIBTRACE_LDFLAGS = -lsystem_trace
-LIBTRACE_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_trace
-LIBUNWIND_LDFLAGS = 
-LIBUNWIND_LDFLAGS[sdk=iphonesimulator*] = -lunwind_sim
+LIBUNWIND_LDFLAGS = -lunwind
 
 OTHER_LDFLAGS = -all_load -L/usr/lib/system -umbrella System $(CR_LDFLAGS) $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBC_LDFLAGS) $(LIBUNWIND_LDFLAGS) $(LIBCLOSURE_LDFLAGS) -ldispatch $(LIBLAUNCH_LDFLAGS) -lxpc $(LIBTRACE_LDFLAGS) $(LIBNOTIFY_LDFLAGS) $(UPWARD_LINKS)
 
 UPWARD_LINKS = -Wl,-upward-lsystem_info
 
 OTHER_LDFLAGS = -all_load -L/usr/lib/system -umbrella System $(CR_LDFLAGS) $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBC_LDFLAGS) $(LIBUNWIND_LDFLAGS) $(LIBCLOSURE_LDFLAGS) -ldispatch $(LIBLAUNCH_LDFLAGS) -lxpc $(LIBTRACE_LDFLAGS) $(LIBNOTIFY_LDFLAGS) $(UPWARD_LINKS)
 
 UPWARD_LINKS = -Wl,-upward-lsystem_info
-UPWARD_LINKS[sdk=iphonesimulator*] = -Wl,-upward-lsystem_sim_info
index fa9af9ed75e1655762459f463fcec1b18b3a9a3d..1c7c2936be51e2efd4c1d32bcd3e0190a9144dda 100644 (file)
@@ -1,3 +1,3 @@
 #include "base.xcconfig"
 
 #include "base.xcconfig"
 
-INSTALL_PATH_ACTUAL = /usr/sbin
+INSTALL_PATH = /usr/sbin
index 51575c9fa563c549a0ac526b78372cbafe2d0025..7eebb22ca2614fca5cdaec3c6b72a7057fe3c6c9 100644 (file)
@@ -1,3 +1,3 @@
 #include "base.xcconfig"
 
 #include "base.xcconfig"
 
-INSTALL_PATH_ACTUAL = /usr/bin
+INSTALL_PATH = /usr/bin