]> 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@
- * 
+ *
  * 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,
  * 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 <assert.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 DEBUG_LIST_FILES 1
+
 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 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)
 {
@@ -231,7 +226,7 @@ _insert_string(char *s, char **l, uint32_t x)
        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;
@@ -249,7 +244,7 @@ _insert_string(char *s, char **l, uint32_t x)
 
        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 *));
@@ -443,8 +438,8 @@ next_word_from_string(char **s)
        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;
@@ -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)
                {
-                       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;
                }
 
@@ -538,7 +533,7 @@ _asl_common_make_dir_path(asl_out_module_t *mlist, uint32_t flags, const char *p
                        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! */
@@ -616,6 +611,70 @@ asl_out_mkpath(asl_out_module_t *mlist, asl_out_rule_t *r)
        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)
 {
@@ -624,19 +683,19 @@ asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len)
 
        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);
        }
-       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);
        }
-       else if (flags & MODULE_FLAG_STYLE_LCL)
+       else if (flags & MODULE_NAME_STYLE_STAMP_LCL)
        {
                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 (flags & MODULE_FLAG_STYLE_LCL_B)
+       else if (flags & MODULE_NAME_STYLE_STAMP_LCL_B)
        {
                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
        {
-               snprintf(buf, len, "%c%lu", STYLE_SEC_PREFIX_CHAR, stamp);
+               snprintf(buf, len, "%c%llu", STYLE_SEC_PREFIX_CHAR, (unsigned long long)stamp);
        }
 }
 
 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->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
        {
@@ -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;
 
+       free(dst->dir);
        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
@@ -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;
 
-       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);
 
@@ -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);
 
-               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;
 
+               if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_FLAG_SYMLINK)) symlink(outpath, dst->path);
                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;
 
-       dst->stamp = time(NULL);
+       dst->timestamp = time(NULL);
 
        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;
 }
 
@@ -1091,9 +1172,9 @@ _asl_out_module_parse_set_param(asl_out_module_t *m, char *s)
                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';
@@ -1204,28 +1285,6 @@ _dst_format_string(char *s)
        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)
 {
@@ -1239,12 +1298,135 @@ _dst_path_match(const char *newpath, const char *existingpath)
        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;
-       char *p, *opts, *path;
+       char *p, *dot, *opts, *path;
        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++)
                {
-                       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';
@@ -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);
@@ -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 (!strcmp(m->name, ASL_MODULE_NAME))
+               if (streq(m->name, ASL_MODULE_NAME))
                {
                        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.
                 */
-               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));
@@ -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;
+
+       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;
 
+       /*
+        * 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);
@@ -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, "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, "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;
 
-                       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;
-
-                       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 */
@@ -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;
                }
+               else if (KEYMATCH(p, "link") || KEYMATCH(p, "symlink"))
+               {
+                       dst->flags |= MODULE_FLAG_SYMLINK;
+               }
                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';
-                               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 ((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;
@@ -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") || !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 */
-       if (!strcmp(dst->fmt, "raw")) dst->tfmt = "sec";
+       if (streq(dst->fmt, "raw")) dst->tfmt = "sec";
 
        /* 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;
        }
 
+       /* 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;
 
@@ -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 (!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 */
-               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)
@@ -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));
-               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;
        }
 
@@ -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->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;
                }
@@ -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;
 
-                       /* 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 */
-                       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 */
@@ -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);
        }
-       else if (*s == '>') 
+       else if (*s == '>')
        {
                _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)
        {
-               if ((x->name != NULL) && (!strcmp(x->name, name))) return x;
+               if ((x->name != NULL) && (streq(x->name, name))) return x;
        }
 
        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)))
                {
-                       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;
@@ -1787,7 +1981,7 @@ _asl_out_module_read_and_merge_dir(asl_out_module_t **list, const char *path, ui
                                        {
                                                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;
@@ -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");
-       assert(sim_root_path);
+       if (sim_root_path == NULL) return NULL;
 
        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);
@@ -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],
-                        (r->query == NULL) ? "" : " ", 
+                        (r->query == NULL) ? "" : " ",
                         (r->query == NULL) ? "" : str,
-                        (r->options == NULL) ? "" : " ", 
+                        (r->options == NULL) ? "" : " ",
                         (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
  */
@@ -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;
+       char tstr[150];
 
        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 = ' ';
                                        }
-                                       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 = ' ';
                                        }
-                                       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)
@@ -2002,6 +2184,11 @@ asl_out_module_print(FILE *f, asl_out_module_t *m)
                                                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);
@@ -2021,11 +2208,45 @@ asl_out_module_print(FILE *f, asl_out_module_t *m)
                                }
                                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;
-                               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);
@@ -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
-_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;
 
+#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;
 
+       extlen = 0;
+       if (ext != NULL) extlen = strlen(ext);
+
        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;
        }
+       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.
  *
- * 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
  *
- * 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
  *
- * 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
  *
- * 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
  *
- * 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
  *
- * 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
@@ -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 MODULE_FLAG_STYLE_SEC (foo.T12345678) */
+       /* check for MODULE_NAME_STYLE_STAMP_SEC (foo.T12345678) */
        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;
        }
 
-       /* 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');
 
-       if (!digits && (!strcmp(stamp + i, ".gz"))) digits = true;
+       if (!digits && (streq(stamp + i, ".gz"))) digits = true;
 
        if (digits)
        {
@@ -2197,25 +2580,34 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp)
                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;
-       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);
        }
-       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
        {
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "_parse_stamp_style fail %u\n", __LINE__);
+#endif
                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)
        {
@@ -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 (zone == '-') utc_offset *= -1;
+               if (zone == '+') utc_offset *= -1;
        }
        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
        {
+#ifdef DEBUG_LIST_FILES
+               fprintf(stderr, "_parse_stamp_style fail %u\n", __LINE__);
+#endif
                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;
 
-       return STAMP_STYLE_UTC_OR_LCL;
+       return STAMP_STYLE_ISO8601;
 }
 
 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;
@@ -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;
 
+#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;
 
@@ -2282,10 +2681,9 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
        {
                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;
@@ -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;
 
+               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;
-               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:
@@ -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 (!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)
                {
@@ -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->stamp = pstyle;
                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)
@@ -2341,11 +2757,14 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
 
                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;
                        }
-                       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;
@@ -2361,7 +2780,7 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
                                                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;
@@ -2374,6 +2793,9 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
                }
                else
                {
+#ifdef DEBUG_LIST_FILES
+                       fprintf(stderr, "asl_list_log_files TIME %s %ld\n", path, x->ftime);
+#endif
                        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)
 {
-       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->base == NULL) return NULL;
 
        /*
         * 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))
                        {
-                               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, '/');
@@ -2455,40 +2879,24 @@ asl_list_src_files(asl_out_dst_data_t *dst)
                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;
        }
 
-       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)
 {
-       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;
-
-       base = strrchr(dst->path, '/');
-       if (base == NULL) return NULL;
-
-       *base = '\0';
-       base++;
+       if (dst->base == NULL) return NULL;
 
        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
@@ -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;
+
        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@
- * 
+ *
  * 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,
@@ -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.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
 
 #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 _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 DEFAULT_TTL 7 /* days */
 #define SECONDS_PER_DAY 86400
+#define DEFAULT_TTL (7 * SECONDS_PER_DAY)
 
 #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_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
 
 typedef struct
 {
+       char *dir;
        char *path;
-       char *fname;
+       char *current_name;
        char *fmt;
-       const char *tfmt;
        char *rotate_dir;
+       char *base;
+       char *ext;
+       const char *tfmt;
+       uint32_t style_flags;
        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;
-       time_t stamp;
+       time_t timestamp;
        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;
+       uint32_t stamp;
        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);
+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);
-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_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_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);
 
index 5bd090cd3967d5e2240178e19dc5a4664f915330..1dcfab1579a2e7819923598cf4300b5c67886d48 100644 (file)
@@ -36,7 +36,6 @@
 
 #define DEFAULT_MAX_RECORDS 2000
 #define DEFAULT_MAX_STRING_MEMORY 4096000
-#define MEM_STRING_HEADER_SIZE 8
 
 #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++)
        {
-               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);
@@ -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->curr_string_mem);
+       snprintf(str, sizeof(str), "%lu", s->curr_string_mem);
        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;
@@ -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 i;
-
        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);
 
@@ -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->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)
        {
+               dispatch_release(out->queue);
                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;
 }
 
+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 *
-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;
-       size_t ss;
 
        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;
+       out->str = malloc(len + 1);
+       if (out->str == NULL)
+       {
+               free(out);
+               return NULL;
+       }
+       
        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 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
@@ -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)
        {
-               ms = (mem_string_t *)s->string_cache[0];
+               ms = s->string_cache[0];
                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)
        {
-               ms = (mem_string_t *)s->string_cache[mid];
+               ms = s->string_cache[mid];
 
                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--;
                        }
@@ -233,7 +289,7 @@ asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash)
                }
                else
                {
-                       ms = (mem_string_t *)s->string_cache[mid];
+                       ms = s->string_cache[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);
        }
 
-       ms = (mem_string_t *)s->string_cache[bot];
+       ms = s->string_cache[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;
@@ -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)
        {
-               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];
                        }
 
@@ -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 (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;
+               free(new);
                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++;
 
@@ -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 (((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)
        {
-               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;
@@ -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];
 
-       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);
+
        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;
        }
 
-       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;
@@ -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);
 
-                       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);
@@ -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 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;
 
-       /* 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;
 }
@@ -728,9 +786,9 @@ asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, asl_msg_t **out)
                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++;
-               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);
        }
@@ -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 i, status;
+       __block uint32_t status;
 
        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 *
@@ -1190,8 +1256,8 @@ asl_memory_slow_match(asl_memory_t *s, mem_record_t *r, asl_msg_t *rawq)
        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;
@@ -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;
 
-       if (s == NULL) return ASL_STATUS_INVALID_STORE;
-       if (res == NULL) return ASL_STATUS_INVALID_ARG;
-
        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;
 }
 
+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)
 {
-       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>
+#include <dispatch/dispatch.h>
 
 typedef struct
 {
        uint32_t hash;
        uint32_t refcount;
-       char str[];
+       char *str;
 } 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;
-       uint32_t kvcount;
        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;
+       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_string_t **string_cache;
+       mem_record_t **record;
+       mem_record_t *buffer_record;
        uint32_t string_count;
-       void **string_cache;
        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);
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@
- * 
- * 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
@@ -1414,9 +137,14 @@ cli_main(int argc, char *argv[])
        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;
+       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;
@@ -1425,6 +153,7 @@ cli_main(int argc, char *argv[])
                debug_log(ASL_LEVEL_ERR, "aslmanager must be run by root\n");
                exit(1);
        }
+#endif
 
        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;
 
+       memset(&opts, 0, sizeof(opts));
+       opts.ttl[LEVEL_ALL] = DEFAULT_TTL;
+       opts.all_max = DEFAULT_MAX_SIZE;
+
        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] != '-'))
                        {
@@ -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)
        {
-               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;
                }
 
@@ -1471,30 +232,55 @@ cli_main(int argc, char *argv[])
        {
                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->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"))
                {
-                       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"))
                {
-                       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"))
                {
-                       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], "-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;
@@ -1516,18 +302,54 @@ cli_main(int argc, char *argv[])
                }
                else if (!strcmp(argv[i], "-dd"))
                {
-                       dryrun = 1;
+                       dryrun = true;
 
                        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);
 
-       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)
        {
@@ -1537,9 +359,13 @@ cli_main(int argc, char *argv[])
                {
                        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");
-       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;
 }
 
+/* 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)
 {
@@ -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.
                         */
-                       if (uid == 0) cli_main(0, NULL);
+
+                       if (uid == geteuid())
+                       {
+                               main_task();
+                       }
                }
                else if (xpc_get_type(request) == XPC_TYPE_ERROR)
                {
                        /* disconnect */
                }
-
-               dispatch_async(serverq, ^__attribute__((noreturn)) { xpc_server_exit(0); });
        });
 
        xpc_connection_resume(peer);
@@ -1593,16 +452,32 @@ main(int argc, char *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 */
-       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. */
-       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);
 
+       cache_delete_register();
+
        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/>
+               <key>com.apple.activity_tracing.cache-delete</key>
+               <true/>
        </dict>
        <key>EnableTransactions</key>
-       <false/>
+       <true/>
+       <key>EnablePressuredExit</key>
+       <true/>
        <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@
  *
@@ -31,7 +31,7 @@
 #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;
@@ -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
- * 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.
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);
 
+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__ */
index 3b29a4a606b6239debe43a201e65165db9d90503..f9338721dafee3da80de7bd44c0a5f020fe13ffc 100644 (file)
 #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;
 
@@ -84,8 +97,13 @@ typedef uint32_t ASL_STATUS;
 #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"
+#endif
 
 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);
+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);
 
index e3d38ab209adba202e0d22d8be71336f56bfdbe7..07a2a2b377bd2f45e252e2e1e2d57fe4cc134277 100644 (file)
 #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
@@ -101,7 +104,7 @@ typedef struct file_string_s
        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
@@ -113,8 +116,10 @@ typedef struct asl_file_s
        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 last_mid;
        uint64_t prev;
        uint64_t cursor;
        uint64_t cursor_xid;
index 104cd9d356ef8a909ff5e8033e902103259aa129..a346ec63af21972608a61a71ae16dbe5dd74f13d 100644 (file)
 #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)
 
-#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
@@ -90,9 +97,10 @@ typedef struct asl_msg_s
        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;
 
@@ -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);
 
+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__ */
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@
  *
 #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>
 
-#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"
 /* 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_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
 
 #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);
@@ -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);
+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 */
index f2fdda03f4f298f5f76a242ded4e1f1f7e0d8055..106aa9016196062a2699ec2dd06a47a2264479f7 100644 (file)
@@ -490,7 +490,7 @@ except that it takes a va_list argument.
 .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
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@
  *
@@ -52,6 +52,8 @@
 #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>
 
 #define FETCH_BATCH    256
 
-#define LEVEL_MASK   0x0000000f
-#define EVAL_MASK    0x000000f0
-#define EVAL_IGNORE  0x00000000
-#define EVAL_ASLFILE 0x00000010
-#define EVAL_SEND    0x00000020
-#define EVAL_TUNNEL  0x00000040
-#define EVAL_FILE    0x00000080
-#define EVAL_QUOTA   0x00000100
+#define EVAL_DEFAULT_ACTION (EVAL_SEND_ASL | EVAL_SEND_TRACE)
+#define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE)
 
 /*
  * Clients get a max of 36000 messages per hour.
 #define NOQUOTA_ENV "ASL_QUOTA_DISABLED"
 #define QUOTA_DISABLED_MSG "*** MESSAGE QUOTA DISABLED FOR THIS PROCESS ***"
 #define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***"
-#define QUOTA_LEVEL 2
-#define QUOTA_LEVEL_STR "2"
+#define QUOTA_LEVEL ASL_LEVEL_CRIT
+#define QUOTA_LEVEL_STR ASL_STRING_CRIT
+
+/*
+ * Limit the size of messages sent to syslogd.
+ */
+#define SIZE_LIMIT_MSG "*** ASL MESSAGE SIZE (%u bytes) EXCEEDED MAXIMIMUM SIZE (%u bytes) ***"
+
+static const 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);
@@ -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.
- * 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)
@@ -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;
+       uint32_t eval;
 
        level = ASL_LEVEL_DEBUG;
        if (slevel >= 0) level = slevel;
-       
+
        val = NULL;
        if ((asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL) == 0) && (val != NULL)) level = atoi(val);
-       
+
        if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
        else if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
 
        if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT))
        {
                /* sending to something other than a client */
-               return (level | EVAL_SEND);
+               return EVAL_ACTIVE | EVAL_SEND_ASL | level;
        }
 
        asl = (asl_client_t *)client;
+       if ((asl != NULL) && (asl->aslfile != NULL)) return (EVAL_ASL_FILE | level);
+
+       if (asl == NULL) asl = _asl_open_default();
        if (asl == NULL)
        {
-               asl = _asl_open_default();
-               if (asl == NULL) return EVAL_IGNORE;
+               eval = EVAL_ACTIVE | EVAL_DEFAULT_ACTION | level;
+               eval &= ~EVAL_SEND_ASL;
+               return eval;
        }
 
-       if (asl->aslfile != NULL) return (level | EVAL_ASLFILE);
-
-       lmask = ASL_FILTER_MASK(level);
+       eval = (asl_client_get_control(asl) & EVAL_ACTION_MASK) | level;
 
        filter = asl->filter & 0xff;
        tunnel = (asl->filter & ASL_FILTER_MASK_TUNNEL) >> 8;
+       if (tunnel != 0) eval |= EVAL_TUNNEL;
+
+       /* 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);
 
@@ -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
  */
-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;
@@ -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 (fmt == NULL)
-               {
-                       if (estr != NULL) free(estr);
-                       return ASL_STATUS_NO_MEMORY;
-               }
+               if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
 
                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)
 {
+       ASL_STATUS status = ASL_STATUS_OK;
        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
- * 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
@@ -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 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;
 }
@@ -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, ...)
 {
-       ASL_STATUS status;
+       ASL_STATUS status = ASL_STATUS_OK;
        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;
 }
@@ -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 status;
+       ASL_STATUS status = ASL_STATUS_OK;
        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;
 }
@@ -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;
-       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)))
        {
@@ -792,15 +865,43 @@ asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *a
        return 0;
 }
 
+/* SPI for SHIM control */
+uint32_t
+asl_set_local_control(asl_object_t client, uint32_t filter)
+{
+       asl_client_t *asl = (asl_client_t *)client;
+       if (asl == NULL)
+       {
+               asl = _asl_open_default();
+               if (asl == NULL) return UINT32_MAX;
+       }
+       else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
+
+       return asl_client_set_control(asl, filter);
+}
+
+uint32_t
+asl_get_local_control(asl_object_t client)
+{
+       asl_client_t *asl = (asl_client_t *)client;
+       if (asl == NULL)
+       {
+               asl = _asl_open_default();
+               if (asl == NULL) return UINT32_MAX;
+       }
+       else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
+
+       return asl_client_get_control(asl);
+}
+
 /*
- * Sets Host, PID, UID, GID, and OSActivityID values in a new message.
+ * Sets PID and OSActivityID values in a new message.
  * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided.
  */
 asl_msg_t *
 asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr)
 {
        char aux_val[64];
-       char aux_host[_POSIX_HOST_NAME_MAX];
        asl_msg_t *aux;
        int status;
        unsigned int osacount = 1;
@@ -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)
        {
-               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);
@@ -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);
 
-       /* Host */
-       memset(&aux_host, 0, _POSIX_HOST_NAME_MAX);
-       if (gethostname(aux_host, _POSIX_HOST_NAME_MAX) == 0) asl_msg_set_key_val(aux, ASL_KEY_HOST, aux_host);
-
        /* PID */
        snprintf(aux_val, sizeof(aux_val), "%u", getpid());
        asl_msg_set_key_val(aux, ASL_KEY_PID, aux_val);
 
-       /* UID */
-       snprintf(aux_val, sizeof(aux_val), "%d", getuid());
-       asl_msg_set_key_val(aux, ASL_KEY_UID, aux_val);
-
-       /* GID */
-       snprintf(aux_val, sizeof(aux_val), "%d", getgid());
-       asl_msg_set_key_val(aux, ASL_KEY_GID, aux_val);
-
        /* OSActivityID */
        if (os_activity_get_active(&osaid, &osacount) == 1)
        {
@@ -849,7 +938,7 @@ asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const
        }
 
        /* 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);
@@ -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 (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;
@@ -944,6 +1033,29 @@ asl_prepared_message(asl_client_t *asl, asl_msg_t *msg)
 }
 #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)
 {
@@ -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;
 
-       if (eval == EVAL_IGNORE) return ASL_STATUS_OK;
+       if ((eval & EVAL_ASL) == 0) return ASL_STATUS_OK;
 
        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;
-               else asl = _asl_open_default();
        }
 
-       level = eval & LEVEL_MASK;
+       level = eval & EVAL_LEVEL_MASK;
        if (level > 7) level = 7;
-       eval &= EVAL_MASK;
        lmask = ASL_FILTER_MASK(level);
 
        if ((objtype == ASL_TYPE_CLIENT) && (asl->aslfile != NULL)) use_global_lock = 1;
@@ -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 (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;
 
@@ -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
         *
-        * Note that we just check /etc/asl/.noquota once, since it would be
+        * We just check /etc/asl/.noquota once, since it would be
         * expensive to stat() for every log message.
+        *
+        * We only check the Environment variable once, since getenv() is
+        * not thread safe.  If someone is changing the environment,
+        * this can crash.
         */
-       
+
        dispatch_once(&noquota_once, ^{
                struct stat sb;
                memset(&sb, 0, sizeof(struct stat));
-               if (stat(NOQUOTA_FILE_PATH, &sb) == 0) _asl_global.quota = UINT32_MAX;
-       });
-       
-       if (_asl_global.quota != UINT32_MAX)
-       {
-               const char *qtest = getenv(NOQUOTA_ENV);
-               if ((qtest != NULL) && (!strcmp(qtest, "1")))
+
+               int save_errno = errno;
+
+               if (stat(NOQUOTA_FILE_PATH, &sb) == 0)
                {
                        _asl_global.quota = UINT32_MAX;
-
-                       qd_msg = asl_base_msg(asl, QUOTA_LEVEL, &tval, sstr, fstr, QUOTA_DISABLED_MSG);
-                       asl_msg_set_key_val(qd_msg, ASL_KEY_OPTION, ASL_OPT_STORE);
                }
-       }
-       
+               else
+               {
+                       const char *qtest = getenv(NOQUOTA_ENV);
+                       if ((qtest != NULL) && (!strcmp(qtest, "1"))) _asl_global.quota = UINT32_MAX;
+               }
+
+               /* 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;
@@ -1115,7 +1216,7 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m
                        }
                        else
                        {
-                               eval &= ~EVAL_SEND;
+                               eval &= ~EVAL_SEND_ASL;
                        }
                }
                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;
@@ -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);
                }
-       
+
                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);
 
@@ -1552,7 +1675,7 @@ _asl_server_control_query(void)
        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);
@@ -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;
-                               return (asl_object_t)fout;
+                               return (asl_object_t)sout;
                        }
                        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@
  *
@@ -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 |= 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 */
@@ -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);
+       client->filter |= (EVAL_ACTIVE | EVAL_SEND_ASL);
 
        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;
 
-       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);
@@ -274,7 +279,7 @@ _do_server_search(asl_msg_t *q)
 
        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);
@@ -367,18 +372,40 @@ asl_client_search(asl_client_t *client, asl_msg_t *query)
 #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 last;
-
        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;
 }
 
+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)
 {
@@ -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].mfmt = NULL;
        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++;
index 3ae25de912aa3fb8c9780c1509d597550eddf5a7..30de51b989b2446f9149e321cdbafb9ec8bc4306 100644 (file)
@@ -53,9 +53,6 @@ const char *ASL_LEVEL_TO_STRING[] =
        ASL_STRING_DEBUG
 };
 
-static char *asl_filesystem_path_database = NULL;
-static char *asl_filesystem_path_archive = NULL;
-
 /*
  * 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;
-       
+
        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;
+       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";
 
-#if TARGET_IPHONE_SIMULATOR
+#if TARGET_OS_SIMULATOR
                asl_var_log = getenv("SIMULATOR_LOG_ROOT");
 #endif
 
@@ -346,12 +345,10 @@ asl_filesystem_path(uint32_t place)
        {
                case ASL_PLACE_DATABASE:
                {
-                       if (asl_filesystem_path_database == NULL) return ASL_PLACE_DATABASE_DEFAULT;
                        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:
@@ -583,25 +580,25 @@ asl_core_str_match(const char *target, const char *mset, uint32_t mincount, uint
 {
        const char *x;
        uint32_t n;
-       
+
        if (length == NULL) length = &n;
-       
+
        if (target == NULL) return (mincount == 0);
-       
+
        for (x = target, *length = 0; *x != '\0'; x++, *length = *length + 1)
        {
                char *s;
-               
+
                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;
-               
+
                break;
        }
-       
+
        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;
-       
+
        if (length == NULL) length = &n;
        *length = 0;
-       
+
        if (target == NULL) return (mincount == 0);
-       
+
        if ((*target == c) && (flags & MFLAG_INCLUDE)) *length = 1;
        if ((*target != c) && (flags & MFLAG_EXCLUDE)) *length = 1;
-       
+
        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;
-       
+
        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;
 }
 
+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)
 {
@@ -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;
-       
+
        if (target == NULL) 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;
        }
-       
+
        /* [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;
-       
+
        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')
@@ -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;
        }
-       
+
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = start + (sign * val);
-       
+
        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;
-       
+
 }
 
 /*
@@ -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;
-       
+
        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;
-       
+
        /* 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;
-       
+
        /* [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;
-       
+
        /* [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;
-       
+
        /* 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;
-       
+
        /* 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')
@@ -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;
        }
-       
+
        t.tm_isdst = -1;
-       
+
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = mktime(&t);
-       
+
        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;
-       
+
        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;
-       
+
        /* . */
        p += len;
        if (*p != '.') return false;
        len = 1;
-       
+
        /* [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;
-       
+
        /* . */
        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;
-       
+
        /* 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;
-       
+
        /* : */
        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;
-       
+
        /* : */
        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;
-       
+
        /* 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;
-       
+
        /* 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;
        }
-       
+
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = timegm(&t);
-       
+
        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;
-       
+
        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;
-       
+
        /* [-] */
        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);
@@ -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;
-       
+
        /* [-] */
        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;
-       
+
        /* 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;
-       
+
        /* [:] */
        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;
-       
+
        /* [:] */
        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;
-       
+
        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;
-               
+
                if (tlen != NULL) *tlen = p - target;
                if (tval != NULL) *tval = mktime(&t);
-               
+
                return true;
        }
-       
+
        /* 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) */
@@ -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;
                }
-               
+
                if (tlen != NULL) *tlen = p - target;
                if (tval != NULL) *tval = timegm(&t);
-               
+
                return true;
        }
-       
+
        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;
-       
+
        /* [:] */
        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;
-       
+
        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')
@@ -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;
        }
-       
+
        if (tlen != NULL) *tlen = p - target;
        if (tval != NULL) *tval = timegm(&t);
-       
+
        return true;
 }
 
@@ -1063,55 +1140,55 @@ asl_core_parse_time(const char *in, uint32_t *tlen)
 {
        time_t tval = 0;
        uint32_t inlen;
-       
+
        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;
-       
+
        /* 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;
        }
-       
+
        /* 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;
        }
-       
+
        /* 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 */
-       
+
        /* 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;
-       
+
        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;
 }
 
+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)
 {
@@ -224,6 +252,8 @@ _asl_file_free_internal(asl_file_t *s)
                s->string_list = x;
        }
 
+       free(s->string_spare);
+
        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 != 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)
                        {
@@ -717,28 +759,34 @@ asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out)
                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);
@@ -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) */
-       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(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);
 
-       /* 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;
@@ -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.
  */
+#define KVSTACK_SIZE 128
+
 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;
+       uint64_t kvstack[KVSTACK_SIZE];
+       uint64_t *kvmalloc = NULL;
        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));
 
+       r.mid = UINT64_MAX;
+       if ((mid != NULL ) && (*mid != 0)) r.mid = *mid;
+
        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;
-       kvlist = NULL;
+       kvlist = kvstack;
 
        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)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        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)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        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)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        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)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        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)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        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)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        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))
                {
-                       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))
                {
@@ -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)
                        {
-                               if (kvlist != NULL) free(kvlist);
+                               free(kvmalloc);
                                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)
                                {
-                                       if (kvlist != NULL) free(kvlist);
+                                       free(kvmalloc);
                                        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;
@@ -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 (*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;
@@ -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);
 
-       free(kvlist);
-       kvlist = NULL;
+       free(kvmalloc);
 
        /* 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
-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;
@@ -1180,12 +1244,14 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle
 
        *out = NULL;
        *outlen = 0;
-       
+
        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;
@@ -1200,6 +1266,38 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle
                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;
 
@@ -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 = ntohs(type);
        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);
@@ -1232,6 +1333,44 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle
        }
 
        *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;
 }
 
@@ -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;
-       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))
@@ -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;
-       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;
@@ -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);
 
-               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);
@@ -1419,7 +1558,7 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, asl_msg_t **msg)
 
                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);
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.
- * 
+ *
  * 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.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
@@ -38,6 +38,7 @@
 #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>
 
 #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
@@ -221,21 +216,132 @@ _asl_msg_std_key(const char *s, uint32_t len)
 #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->asl_type = type;
 
        return out;
 }
@@ -259,28 +365,33 @@ static const char *
 _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 (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:
                {
-                       return page->data + page->key[slot];
+                       return page->data + k;
                }
                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];
                        }
-                       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];
                        }
 
@@ -288,7 +399,7 @@ _asl_msg_slot_key(asl_msg_t *page, uint32_t slot)
                }
                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;
                }
@@ -301,22 +412,26 @@ static const char *
 _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 (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)
        {
-               return page->data + page->val[slot];
+               return page->data + v;
        }
        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;
        }
@@ -332,7 +447,7 @@ asl_msg_new(uint32_t type)
 {
        asl_msg_t *out;
 
-       out = _asl_msg_make_page();
+       out = _asl_msg_make_page(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)
 {
-       uint32_t i;
+       uint32_t i, mslots;
        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);
                }
 
-               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);
                }
 
-               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);
                }
        }
@@ -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)
 {
-       int i, page1 = 1;
+       uint32_t i, mslots, page1 = 1;
 
        if (f == NULL) return;
        if (msg == NULL)
@@ -465,6 +585,8 @@ _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg)
                return;
        }
 
+       mslots = _slot_count(msg);
+
        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);
 
-               for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
+               for (i = 0; i < mslots; 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, " ");
-                       _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;
@@ -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)
 {
-       uint32_t i, len, slot;
+       uint32_t i, len, slot, mslots;
        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;
+       mslots = _slot_count(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
        {
-               if (page->key[slot] != ASL_MSG_SLOT_FREE)
+               if (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE)
                {
                        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
                        {
-                               kp = page->data + page->key[slot];
+                               kp = page->data + _get_slot_key(page, slot);
                                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;
 
-               if (slot >= ASL_MSG_PAGE_SLOTS)
+               if (slot >= mslots)
                {
                        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)
 {
-       uint32_t i, sx;
+       uint32_t i, sx, mslots;
        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;
 
+       mslots = _slot_count(msg);
+
        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 */
-               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)
                                {
@@ -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.
@@ -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 p, xpn, xsn;
+       uint32_t p, xpn, xsn, mslots;
        asl_msg_t *page = NULL;
 
        if (msg == NULL) return IndexNull;
 
+       mslots = _slot_count(msg);
+
        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 (opout != NULL) *opout = (uint32_t)(page->op[xsn]);
+       if (opout != NULL) *opout = _get_slot_op(page, 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;
@@ -659,7 +787,7 @@ asl_msg_fetch(asl_msg_t *msg, uint32_t x, const char **keyout, const char **valo
                        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;
@@ -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 (opout != NULL) *opout = (uint32_t)(page->op[slot]);
+       if (opout != NULL) *opout = _get_slot_op(page, slot);
 
        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)
 {
-       uint32_t slot, i;
+       uint32_t slot, i, mslots;
        asl_msg_t *page;
 
        if (msg == NULL) return NULL;
 
+       mslots = _slot_count(msg);
+
        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++;
@@ -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)
 {
-       uint32_t slot, keylen, vallen, total;
+       uint32_t slot, keylen, vallen, total, mslots;
        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;
 
+       mslots = _slot_count(msg);
+
+       o = op;
        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 */
-                       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 */
-               page = _asl_msg_make_page();
+               page = _asl_msg_make_page(msg->asl_type);
                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)
        {
-               page->key[slot] = kx;
+               k = kx;
        }
        else if (extkey == NULL)
        {
-               page->key[slot] = page->data_size;
+               k = page->data_size;
                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;
        }
 
+       _set_slot_key(page, slot, k);
        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)
                {
-                       page->val[slot] = page->data_size;
+                       v = page->data_size;
                        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;
                }
 
+               _set_slot_val(page, slot, v);
                page->data_size += vallen;
        }
 
        /* set op */
-       page->op[slot] = (uint16_t)op;
+       _set_slot_op(page, slot, o);
 
        /* 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)
 {
-       uint32_t i, slot, newexternal;
+       uint32_t i, slot, mslots, newexternal;
        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;
 
+       mslots = _slot_count(msg);
+
        slot = IndexNull;
        page = NULL;
 
+       o = op;
+
        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;
 
-       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
                {
-                       intval = page->data + page->val[slot];
+                       intval = page->data + v;
                        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);
                }
 
-               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)))
        {
-               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)))
        {
-               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
-        * 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))
        {
-               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->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);
@@ -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 */
-               i = page->val[slot] & ASL_MSG_OFFSET_MASK;
+               i = v & ASL_MSG_OFFSET_MASK;
 
                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);
-                       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 */
-                       page->val[slot] = i;
+                       _set_slot_val(page, slot, i);
                        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;
        }
 
@@ -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);
-                       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 */
-                       page->val[slot] = i;
+                       _set_slot_val(page, slot, i);
                        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 */
-       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->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);
 }
@@ -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;
 
+       if (msg == NULL) return -1;
+       if (key == NULL) return -1;
+
        /* 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;
+       uint16_t k, v;
 
        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);
        }
 
-       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->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--;
 }
@@ -1798,8 +1950,8 @@ _asl_time_string(const char *infmt, const char *str, const char *nano)
                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;
@@ -1815,8 +1967,8 @@ _asl_time_string(const char *infmt, const char *str, const char *nano)
                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;
@@ -1824,7 +1976,7 @@ _asl_time_string(const char *infmt, const char *str, const char *nano)
 
        if ((!strcasecmp(fmt, "sec")) || (!strcasecmp(fmt, "raw")))
        {
-               asprintf(&out, "%lu%s", tick, nanobuf);
+               asprintf(&out, "%llu%s", (unsigned long long) tick, nanobuf);
                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;
 
-               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;
 }
 
+#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
 
@@ -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 (op != NULL) *op = page->op[slot];
+       if (op != NULL) *op = _get_slot_op(page, slot);
+
        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)
 {
-       int type = ASL_TYPE_CLIENT;
+       uint32_t type = ASL_TYPE_CLIENT;
 
        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;
-       char *path;
+       char path[MAXPATHLEN];
        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 (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)
        {
-               if (errno != ENOENT)
-               {
-                       free(path);
-                       return ASL_STATUS_FAILED;
-               }
+               if (errno != ENOENT) return ASL_STATUS_FAILED;
 
                sd = fopen(path, "w+");
-               free(path);
 
                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+");
-               free(path);
 
                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)
 {
-       char *path  = NULL;
+       char *path = NULL;
 
        *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;
-       char *path, *tmp_path, *tstring, *scratch;
+       char *path;
+       char tstring[128], tmp_path[MAXPATHLEN];
        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;
 
-       tstring = NULL;
        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;
-               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
        {
-               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);
-       free(tstring);
-       tstring = NULL;
-
        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)
                {
-                       tmp_path = NULL;
-
                        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 */
-                               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);
                }
@@ -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)
 {
-       char *tstring = NULL;
+       char tstring[MAXPATHLEN];
        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);
@@ -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 (!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 */
-                       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 */
-                       free(tstring);
                        return ASL_STATUS_FAILED;
                }
        }
 
-       free(tstring);
        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;
-       char *path, *dir, *tstring;
+       char *path;
+       char tstring[128], dir[128];
        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;
 
-       dir = NULL;
        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;
-               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
        {
-               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);
-       if (status != ASL_STATUS_OK)
-       {
-               free(dir);
-               return status;
-       }
+       if (status != ASL_STATUS_OK) return status;
 
        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);
-       free(tstring);
        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;
-       char *path;
+       char path[MAXPATHLEN];
        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;
 
-               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);
-               if (path != NULL) free(path);
                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;
-       char *path;
+       char path[MAXPATHLEN];
        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;
 
-               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,
@@ -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);
-               if (path != NULL) free(path);
                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;
-       uint32_t status = ASL_STATUS_FAILED;
 
        if (query == NULL)
        {
@@ -1160,7 +1114,6 @@ _jump_search(asl_object_private_t *obj, asl_object_private_t *query)
                asl_msg_list_release(ql);
        }
 
-       if (status != ASL_STATUS_OK) return NULL;
        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@
  *
@@ -38,6 +38,9 @@
 #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)
 {
@@ -53,7 +56,7 @@ asl_string_new(uint32_t encoding)
        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;
 }
 
@@ -90,6 +93,13 @@ asl_string_release_return_bytes(asl_string_t *str)
        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 */
@@ -98,7 +108,7 @@ asl_string_release_return_bytes(asl_string_t *str)
                        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);
@@ -120,6 +130,14 @@ char *
 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;
 }
 
@@ -166,7 +184,7 @@ _asl_string_grow(asl_string_t *str, size_t len)
                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;
@@ -208,32 +226,26 @@ asl_string_append_char_no_encoding(asl_string_t *str, const char c)
 
        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 (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 *
-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;
 
-       applen = strlen(app);
+       applen = copylen;
+       if (applen == 0) applen = strlen(app);
+
        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';
 
-       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 *
+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)
 {
-       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;
@@ -267,33 +279,91 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
        {
                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;
 
+                       s = NULL;
+                       copylen = 0;
+
                        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
                                {
-                                       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:
                {
+                       s = NULL;
+                       copylen = 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)
                                        {
-                                               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;
                                        }
 
-                                       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;
                                }
@@ -320,26 +404,48 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
                                {
                                        if (encode_space == 0)
                                        {
-                                               asl_string_append_char_no_encoding(str, ' ');
+                                               if (s == NULL) s = p;
+                                               copylen++;
                                                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))
                                {
-                                       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)))
                                {
-                                       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;
                                }
 
@@ -348,10 +454,24 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
                                {
                                        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_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;
                                }
 
@@ -360,16 +480,34 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
                                {
                                        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, 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))
                                {
+                                       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;
@@ -380,56 +518,133 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
                                {
                                        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, '\\');
                                        }
 
+                                       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, 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:
                {
+                       s = NULL;
+                       copylen = 0;
+
                        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 == '<')
                                {
-                                       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 == '>')
                                {
-                                       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 == '"')
                                {
-                                       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 == '\'')
                                {
-                                       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))
                                {
+                                       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);
-                                       asl_string_append_no_encoding(str, tmp);
+                                       asl_string_append_no_encoding_len(str, tmp, 6);
                                }
                                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:
                {
@@ -514,19 +729,19 @@ asl_string_append_op(asl_string_t *str, uint32_t op)
        }
 
        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_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_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;
 }
 
index 2965f9721afbc24c55974f97aa3061eaa66f1654..45f940909cbdf924fc549020a2d433373fefcfd5 100644 (file)
@@ -35,6 +35,7 @@
 #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+/";
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@
  *
@@ -65,6 +65,8 @@
 #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>
@@ -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;
-__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__ 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 */
 
+#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).
  */
+
+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)
-       int pri;
-       char *fmt;
-       va_dcl
+int pri;
+char *fmt;
+va_dcl
 #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__
-       va_start(ap, fmt);
+               va_start(ap, fmt);
 #else
-       va_start(ap);
+               va_start(ap);
 #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
@@ -162,7 +235,7 @@ openlog(const char *ident, int opts, int logfac)
 
        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);
index 566416bfd0e384170975163d5cb48f7a46986141..31b71001dddc721ce47ab27bbe1a79b6326b85e5 100644 (file)
@@ -33,7 +33,6 @@
                        isa = PBXAggregateTarget;
                        buildConfigurationList = 3FFD4402174862D0007DAC1B /* Build configuration list for PBXAggregateTarget "executables_Sim" */;
                        buildPhases = (
-                               3F5F5B9C17487ADB00C12281 /* Configuration */,
                        );
                        dependencies = (
                                3FFD440717486325007DAC1B /* PBXTargetDependency */,
@@ -59,6 +58,7 @@
 
 /* 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, ); }; };
                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 */; };
+               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, ); }; };
 /* 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;
-                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man3";
+                       dstPath = /usr/share/man/man3;
                        dstSubfolderSpec = 0;
                        files = (
                                3F6F44141613AAA600CA9ADB /* asl.3 in Install man3 */,
                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 */,
                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 */,
                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 */,
                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 */,
 /* 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>"; };
                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>"; };
+               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>"; };
                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>"; };
                        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 */,
                        );
                08FB7794FE84155DC02AAC07 /* syslog */ = {
                        isa = PBXGroup;
                        children = (
+                               2DEE8C421AE575AB007B5CBE /* CacheDelete.framework */,
+                               2DEE8C401AE575A2007B5CBE /* CoreFoundation.framework */,
                                505ACBA1108FD18400197086 /* aslcommon */,
                                503917691091404D0001165E /* aslmanager */,
                                503917C41091412B0001165E /* util */,
                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 */,
+                               2D30D27F1AE6C84200673818 /* daemon.c */,
+                               2D30D2801AE6C84200673818 /* daemon.h */,
                                5039176D1091408B0001165E /* com.apple.aslmanager.plist */,
                        );
                        name = aslmanager;
                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 */,
                                50391764109140450001165E /* Frameworks */,
                                503A82631099037D00B0D08A /* Copy Manpage.8 */,
                                FCAC6D7410AB34C9008DEAC9 /* ShellScript */,
+                               2D30D27D1AE6BBA000673818 /* Copy CacheDelete plist */,
                        );
                        buildRules = (
                        );
 /* 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;
                        );
                        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 */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               2D30D2811AE6C84200673818 /* daemon.c in Sources */,
                                5039176F1091408B0001165E /* aslmanager.c in Sources */,
+                               2DEE8C461AE5798B007B5CBE /* cache_delete.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                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",
                                );
+                               OTHER_LDFLAGS = "";
                                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
+    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
+    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
 
-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
 
-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
 
-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
+
+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.
-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
-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.
@@ -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 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.
@@ -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.
+.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
-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
+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 
@@ -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
-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,
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;
-               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);
        }
@@ -529,8 +529,8 @@ _asl_dir_today_close(asl_out_rule_t *r)
        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;
 }
@@ -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)
 {
-       char tmpfname[MAXPATHLEN], *fn;
+       char tmpcurrent_name[MAXPATHLEN], *fn;
 
        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;
-               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 ((r->dst->size == 0) || (r->dst->stamp == 0))
+       if ((r->dst->size == 0) || (r->dst->timestamp == 0))
        {
                struct stat sb;
 
@@ -568,8 +568,8 @@ _act_checkpoint(asl_out_rule_t *r, uint32_t force)
                        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;
        }
        
@@ -583,19 +583,21 @@ _act_checkpoint(asl_out_rule_t *r, uint32_t force)
        {
                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(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);
-               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;
 }
@@ -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);
-       if (status == 1) trigger_aslmanager();
+       if (status == 1) asl_trigger_aslmanager();
 
        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;
                }
 
-               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
        {
-               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;
@@ -687,22 +689,22 @@ _asl_dir_today_open(asl_out_rule_t *r, const time_t *tick)
 #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)
        {
-               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)
        {
-               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;
        }
 
@@ -729,7 +731,7 @@ _asl_dir_today_open(asl_out_rule_t *r, const time_t *tick)
                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;
 }
@@ -746,7 +748,7 @@ _asl_file_close(asl_out_rule_t *r)
        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);
        }
@@ -796,18 +798,18 @@ _asl_file_open(asl_out_rule_t *r)
        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);
 
-       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)
        {
-               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;
        }
 
@@ -830,7 +832,7 @@ _asl_file_open(asl_out_rule_t *r)
                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;
 }
 
@@ -843,7 +845,7 @@ _text_file_close(asl_out_rule_t *r)
        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);
        }
@@ -969,12 +971,12 @@ _act_dst_close(asl_out_rule_t *r, int why)
        }
        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)
        {
-               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);
        }
 }
@@ -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;
 
-                       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))
        {
-               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;
        }
 
@@ -1449,7 +1451,7 @@ _act_file_checkpoint_all(uint32_t force)
                if (_act_file_checkpoint(m, NULL, force) > 0) did_checkpoint = 1;
        }
 
-       trigger_aslmanager();
+       asl_trigger_aslmanager();
 
        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;
 
+       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;
@@ -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;
 
-                       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
-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);
@@ -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);
 
+               /* 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);
 
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
-bsd_out_message(asl_msg_t *msg)
+bsd_out_message(asl_msg_t *msg, int64_t msize)
 {
        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);
+
+               /* end of the output module chain (after asl) - decrement global memory stats */
+               OSAtomicAdd64(-1ll * msize, &global.memory_size);
+
                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 <asl_private.h>
 #include "daemon.h"
 
 #define LIST_SIZE_DELTA 256
+#define STATS_TABLE_SIZE 256
 
 #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 aslmanager_triggered = 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
 
+#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 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_STATS_INTERVAL 600
+
+#define ASL_STATS_LEVEL 5
 
 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"
 };
 
-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)
@@ -146,12 +256,42 @@ kern_quota_check(time_t now, asl_msg_t *msg, uint32_t level)
        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;
 
+       if (global.hostname != NULL) return global.hostname;
+
        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)
 {
-       const char *val, *fac, *ruval, *rgval;
+       const char *val, *fac, *ruval, *rgval, *sval = NULL;
        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 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);
+
+               sval = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PROC);
        }
 
        /* 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);
 
+
        /* 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 */
-       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 */
@@ -365,19 +508,21 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *
        }
 
        /* 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:
                        {
-                               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:
                        {
-                               asl_msg_set_key_val(msg, ASL_KEY_SENDER, "syslogd");
+                               sval = "syslogd";
+                               asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval);
                                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");
+               sval = NULL;
        }
 
        /* 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")))
        {
-               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))
        {
-               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);
        }
 
@@ -462,6 +608,11 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *
                disaster_message(msg);
        }
 
+       /*
+        * gather sender stats
+        */
+       if (source != SOURCE_INTERNAL) stats_msg(sval, now, msg);
+
        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.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);
@@ -603,7 +755,22 @@ control_set_param(const char *s, bool eval)
                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);
@@ -643,12 +810,20 @@ control_set_param(const char *s, bool eval)
                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);
-               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"))
@@ -752,7 +927,6 @@ void
 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;
 
@@ -760,38 +934,24 @@ process_message(asl_msg_t *msg, uint32_t source)
 
        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;
 
-       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);
 
-               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);
-               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);
+
        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);
 
-                       /* 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);
 
-               OSAtomicAdd64(-1ll * msize, &global.work_queue_size);
                OSAtomicDecrement32(&global.work_queue_count);
+               vproc_transaction_end(NULL, vt);
        });
 }
 
@@ -846,34 +1010,6 @@ internal_log_message(const char *str)
        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, ...)
 {
@@ -887,6 +1023,9 @@ asldebug(const char *str, ...)
        if (dfp == NULL) return 0;
 
        va_start(v, str);
+       fprintf(dfp, "W %d %llu", global.work_queue_count, global.memory_size);
+       if (global.memory_db != NULL) fprintf(dfp, "   M %u %u %lu", global.memory_db->record_count, global.memory_db->string_count, global.memory_db->curr_string_mem);
+       fprintf(dfp, " ; ");
        vfprintf(dfp, str, v);
        va_end(v);
 
@@ -1200,7 +1339,7 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se
        /* 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);
@@ -1209,7 +1348,7 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se
        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);
        }
 
index 93de9f000526ff600bc18778b7132d5c356fd758..106059b17c1d6167efc57baef5ade3bd40dc747b 100644 (file)
@@ -91,8 +91,21 @@ extern const char *_path_syslogd_log;
 
 #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
 {
@@ -118,7 +131,8 @@ struct global_s
        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;
@@ -134,11 +148,13 @@ struct global_s
        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;
+       char *hostname;
        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;
-       int64_t max_work_queue_size;
+       time_t stats_interval;
+       int64_t memory_max;
 };
 
 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);
-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);
 
-void trigger_aslmanager();
-
 /* 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@
  * 
@@ -37,6 +37,7 @@
 #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>
@@ -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 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;
@@ -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);
-                       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)))
        {
-               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);
        }
 
-       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)))
@@ -1010,22 +1025,132 @@ syslogd_state_query(asl_msg_t *q, asl_msg_list_t **res, uid_t uid)
        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.
+ *
+ * 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;
-       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;
-
        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;
 
@@ -1071,84 +1196,15 @@ database_server()
                        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;
 
-       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);
@@ -1420,6 +1476,54 @@ __asl_server_prune
        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
 (
@@ -1429,51 +1533,47 @@ __asl_server_message
        audit_token_t token
 )
 {
-       asl_msg_t *msg;
-       char tmp[64];
        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;
        }
 
-       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;
        }
 
-       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);
 
-       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);
 
-       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;
 }
@@ -1574,7 +1674,7 @@ __asl_server_create_aux_link
 
        *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);
index a050abadfc42c761c5c0548012db917802be42c0..f8c4cd55372a01ef09c4e6ecfa22e467521777b3 100644 (file)
@@ -619,6 +619,12 @@ session(void *x)
                                                }
                                                else
                                                {
+                                                       free(out);
+                                                       out = NULL;
+
+                                                       asl_msg_list_release(res);
+                                                       res = NULL;
+
                                                        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;
+       uint64_t master_val;
 #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;
@@ -650,6 +651,11 @@ main(int argc, const char *argv[])
         */
        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();
 
index 3f6affd3461e6ad5ed9a5a588ba0e5ad999bcbe9..75557880d5491ef98f786abe5c51568c01731d2d 100644 (file)
@@ -184,7 +184,6 @@ udp_in_init()
        return 0;
 }
 
-/* N.B. Does NOT close fds.  They "belong" to launchd. */
 int
 udp_in_close(void)
 {
@@ -203,6 +202,7 @@ udp_in_close(void)
 
                if (ufd[i] != -1)
                {
+                       close(ufd[i]);
                        ufd[i] = -1;
                }
        }
index e2d6a7379a0bfea89cc5a1ae249551b6bf648b1f..0e3b4e7f2fdf3c44d5cee10ddba71b45ac94ee3c 100644 (file)
@@ -62,7 +62,7 @@ key val
 .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
@@ -717,15 +717,15 @@ time sending messages that are in most cases unnecessary.
 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
-filter.
+filter mask.
 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
@@ -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 master filter may be unset with:
+The master filter mask may be deactivated with:
 .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.
@@ -752,11 +752,11 @@ In this case,
 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
-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
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@
  * 
@@ -136,15 +136,27 @@ static uint32_t dbselect = DB_SELECT_SYSLOGD;
 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);
 
-//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_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;
@@ -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);
 
+#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
-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, "%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 *
@@ -259,6 +321,16 @@ module_control(int argc, char *argv[])
        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)
@@ -389,10 +461,10 @@ module_control(int argc, char *argv[])
                        fprintf(stderr, "can't allocate memory - exiting\n");
                        exit(-1);
                }
-               
+
                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);
@@ -512,7 +584,7 @@ rcontrol_get_string(const char *name, int *val)
 }
 
 int
-rcontrol_set_string(const char *name, int filter)
+rcontrol_set_string(const char *name, uint32_t bits)
 {
        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;
 
-       x = filter;
+       x = bits;
        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;
 }
 
+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)
 {
@@ -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)
                {
-                       printf("Master filter mask: %s\n", asl_filter_string(filter));
+                       printf("Master settings: ");
+                       print_eval_bits(filter);
                        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)
        {
-               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;
        }
 
-       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
-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;
@@ -729,7 +815,7 @@ rcontrol_set(pid_t pid, uid_t uid, int filter)
 
        if (pid < 0)
        {
-               status = rcontrol_set_string(rcname, filter);
+               status = rcontrol_set_string(rcname, bits);
 
                if (status == NOTIFY_STATUS_OK)
                {
@@ -741,7 +827,7 @@ rcontrol_set(pid_t pid, uid_t uid, int filter)
                return -1;
        }
 
-       status = rcontrol_set_string(rcname, filter);
+       status = rcontrol_set_string(rcname, bits);
        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;
-       char myname[MAXHOSTNAMELEN + 1];
+       char host_name[MAXHOSTNAMELEN + 1];
 
        if (msg == NULL) return 0;
 
@@ -787,14 +873,14 @@ rsend(asl_msg_t *msg, char *rhost)
 
        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 (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);
@@ -821,7 +907,7 @@ rlegacy(char *msg, int level, char *rhost)
        int s;
        struct sockaddr_in dst;
        struct hostent *h;
-       char myname[MAXHOSTNAMELEN + 1];
+       char host_name[MAXHOSTNAMELEN + 1];
 
        if (msg == NULL) return 0;
 
@@ -841,9 +927,9 @@ rlegacy(char *msg, int level, char *rhost)
        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));
 
@@ -852,6 +938,230 @@ rlegacy(char *msg, int level, char *rhost)
        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)
 {
@@ -917,20 +1227,24 @@ asl_string_to_char_level(const char *s)
 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;
        }
 
+       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;
 
@@ -966,36 +1280,78 @@ syslog_remote_control(int argc, char *argv[])
 
        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
                {
-                       mask = asl_string_to_filter(argv[3]);
+                       mask = asl_string_to_filter(argv[i]);
                        if (mask < 0)
                        {
-                               printf("unknown syslog mask: %s\n", argv[3]);
+                               printf("can't understand mask: %s\n", argv[i]);
                                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[])
 {
-       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;
+       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;
@@ -1026,16 +1382,42 @@ syslog_send(int argc, char *argv[])
                        }
                        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;
 
@@ -1065,7 +1447,7 @@ syslog_send(int argc, char *argv[])
 
        if (rhost == NULL)
        {
-               asl_client_send(asl, m);
+               asl_send(asl, (asl_object_t)m);
        }
        else if (rfmt == SEND_FORMAT_ASL)
        {
@@ -1080,7 +1462,7 @@ syslog_send(int argc, char *argv[])
 
        if (str != NULL) free(str);
 
-       asl_client_release(asl);
+       asl_release(asl);
 
        return 0;
 }
@@ -1096,6 +1478,15 @@ syslog_config(int argc, char *argv[])
        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();
@@ -1156,6 +1547,15 @@ syslog_control(int argc, char *argv[])
        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)
        {
@@ -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);
 
-       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);
@@ -1538,15 +1938,15 @@ sort_compare_key(asl_msg_t *a, asl_msg_t *b, const char *key)
 }
 
 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;
 
-       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);
@@ -1921,13 +2321,14 @@ main(int argc, char *argv[])
 
        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++)
        {
-               if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
-               {
-                       usage();
-                       exit(0);
-               }
 
                if ((!strcmp(argv[i], "-time")) || (!strcmp(argv[i], "--time")))
                {
@@ -1936,6 +2337,12 @@ main(int argc, char *argv[])
                        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);
@@ -2113,7 +2520,7 @@ main(int argc, char *argv[])
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
-                               usage();
+                               usage(HELP_SEARCH);
                                exit(1);
                        }
 
@@ -2126,7 +2533,7 @@ main(int argc, char *argv[])
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
-                               usage();
+                               usage(HELP_SEARCH);
                                exit(1);
                        }
 
@@ -2143,7 +2550,7 @@ main(int argc, char *argv[])
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
-                               usage();
+                               usage(HELP_SEARCH);
                                exit(1);
                        }
 
@@ -2178,7 +2585,7 @@ main(int argc, char *argv[])
                        if ((i + 1) >= argc)
                        {
                                asl_msg_list_release(qlist);
-                               usage();
+                               usage(HELP_SEARCH);
                                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");
-                                       usage();
+                                       usage(HELP_SEARCH);
                                        exit(1);
                                }
                        }
@@ -2359,22 +2766,22 @@ main(int argc, char *argv[])
                        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_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);
-               
+
                if (qmin > 0) qmin--;
                tail_count = 0;
        }
index fa9af9ed75e1655762459f463fcec1b18b3a9a3d..1c7c2936be51e2efd4c1d32bcd3e0190a9144dda 100644 (file)
@@ -1,3 +1,3 @@
 #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>/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
 
-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
-LIBCLOSURE_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_blocks
 LIBC_LDFLAGS = -lsystem_c
-LIBC_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_c
 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
-LIBM_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_m
 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
-UPWARD_LINKS[sdk=iphonesimulator*] = -Wl,-upward-lsystem_sim_info
index fa9af9ed75e1655762459f463fcec1b18b3a9a3d..1c7c2936be51e2efd4c1d32bcd3e0190a9144dda 100644 (file)
@@ -1,3 +1,3 @@
 #include "base.xcconfig"
 
-INSTALL_PATH_ACTUAL = /usr/sbin
+INSTALL_PATH = /usr/sbin
index 51575c9fa563c549a0ac526b78372cbafe2d0025..7eebb22ca2614fca5cdaec3c6b72a7057fe3c6c9 100644 (file)
@@ -1,3 +1,3 @@
 #include "base.xcconfig"
 
-INSTALL_PATH_ACTUAL = /usr/bin
+INSTALL_PATH = /usr/bin