]> git.saurik.com Git - apple/syslog.git/commitdiff
syslog-148.7.tar.gz mac-os-x-108 mac-os-x-1081 v148.7
authorApple <opensource@apple.com>
Thu, 31 May 2012 00:44:10 +0000 (00:44 +0000)
committerApple <opensource@apple.com>
Thu, 31 May 2012 00:44:10 +0000 (00:44 +0000)
24 files changed:
aslcommon/asl_memory.c
aslcommon/asl_memory.h
aslcommon/asl_mini_memory.c
aslcommon/asl_mini_memory.h
aslmanager.tproj/aslmanager.c
syslog.xcodeproj/project.pbxproj
syslogd.tproj/after_install.sh
syslogd.tproj/asl.conf.5
syslogd.tproj/asl_action.c
syslogd.tproj/asl_in.c [deleted file]
syslogd.tproj/bb_convert.c
syslogd.tproj/bsd_in.c
syslogd.tproj/bsd_out.c
syslogd.tproj/com.apple.syslogd.plist
syslogd.tproj/daemon.c
syslogd.tproj/daemon.h
syslogd.tproj/dbserver.c
syslogd.tproj/klog_in.c
syslogd.tproj/remote.c
syslogd.tproj/syslogd.8
syslogd.tproj/syslogd.c
syslogd.tproj/udp_in.c
util.tproj/syslog.1
util.tproj/syslog.c

index e0a81d1ee29de269579106c4905bd07a264cbba7..f0f94787b5638c9ecfee141145fec1657b0201ea 100644 (file)
@@ -199,11 +199,10 @@ asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash)
                return 1;
        }
 
-       top = s->string_count - 1;
+       range = top = s->string_count - 1;
        bot = 0;
        mid = top / 2;
 
-       range = top - bot;
        while (range > 1)
        {
                ms = (mem_string_t *)s->string_cache[mid];
@@ -1129,7 +1128,6 @@ asl_memory_match(asl_memory_t *s, aslresponse query, aslresponse *res, uint64_t
        if (s == NULL) return ASL_STATUS_INVALID_STORE;
        if (res == NULL) return ASL_STATUS_INVALID_ARG;
 
-       do_match = 1;
        qp = NULL;
        qtype = NULL;
        rescount = 0;
index d6c99fc78e7eea74699f0ae1f563dfcbc21a0563..a39821d8ad7dfe1b366a1a2b969e316e2dab018b 100644 (file)
@@ -76,4 +76,4 @@ uint32_t asl_memory_fetch(asl_memory_t *s, uint64_t mid, aslmsg *msg, int32_t ru
 
 uint32_t asl_memory_match(asl_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid);
 
-#endif __ASL_MEMORY_H__
+#endif /* __ASL_MEMORY_H__ */
index 8510a0776fdfa419ac49938e7b7542658f8f9a5d..5d9d79aacee4f794d0124eb1aa0d06a53eae8560 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <asl_core.h>
 #include "asl_mini_memory.h"
-#include <unistd.h>x
+#include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <sys/errno.h>
@@ -204,11 +204,10 @@ asl_mini_memory_string_cache_search_hash(asl_mini_memory_t *s, uint32_t hash)
                return 1;
        }
 
-       top = s->string_count - 1;
+       range = top = s->string_count - 1;
        bot = 0;
        mid = top / 2;
 
-       range = top - bot;
        while (range > 1)
        {
                ms = (mini_mem_string_t *)s->string_cache[mid];
@@ -400,6 +399,7 @@ asl_mini_memory_message_encode(asl_mini_memory_t *s, aslmsg msg)
        r->level = ASL_LEVEL_DEBUG;
        r->pid = -1;
        r->time = (uint64_t)-1;
+       r->nano = (uint32_t)-1;
 
        key = NULL;
        val = NULL;
@@ -412,6 +412,10 @@ asl_mini_memory_message_encode(asl_mini_memory_t *s, aslmsg msg)
                {
                        if (val != NULL) r->time = asl_parse_time(val);
                }
+               else if (!strcmp(key, ASL_KEY_TIME_NSEC))
+               {
+                       if (val != NULL) r->nano = atoi(val);
+               }
                else if (!strcmp(key, ASL_KEY_SENDER))
                {
                        if (val != NULL) r->sender = asl_mini_memory_string_retain(s, val, 1);
@@ -591,6 +595,13 @@ asl_mini_memory_message_decode(asl_mini_memory_t *s, mini_mem_record_t *r, aslms
                asl_set(msg, ASL_KEY_TIME, tmp);
        }
 
+       /* Nanoseconds */
+       if (r->nano != (uint32_t)-1)
+       {
+               snprintf(tmp, sizeof(tmp), "%u", r->nano);
+               asl_set(msg, ASL_KEY_TIME_NSEC, tmp);
+       }
+
        /* Sender */
        if (r->sender != NULL)
        {
@@ -719,6 +730,20 @@ asl_mini_memory_query_to_record(asl_mini_memory_t *s, asl_msg_t *q, uint32_t *ty
                        *type |= ASL_QUERY_MATCH_TIME;
                        out->time = asl_parse_time(val);
                }
+               else if (!strcmp(key, ASL_KEY_TIME_NSEC))
+               {
+                       if (val == NULL) continue;
+
+                       if (*type & ASL_QUERY_MATCH_NANO)
+                       {
+                               asl_mini_memory_record_free(s, out);
+                               *type = ASL_QUERY_MATCH_SLOW;
+                               return NULL;
+                       }
+
+                       *type |= ASL_QUERY_MATCH_NANO;
+                       out->nano = atoll(val);
+               }
                else if (!strcmp(key, ASL_KEY_LEVEL))
                {
                        if (val == NULL) continue;
@@ -864,6 +889,7 @@ asl_mini_memory_fast_match(asl_mini_memory_t *s, mini_mem_record_t *r, uint32_t
 
        if ((qtype & ASL_QUERY_MATCH_MSG_ID) && (q->mid != r->mid)) return 0;
        if ((qtype & ASL_QUERY_MATCH_TIME) && (q->time != r->time)) return 0;
+       if ((qtype & ASL_QUERY_MATCH_NANO) && (q->nano != r->nano)) return 0;
        if ((qtype & ASL_QUERY_MATCH_LEVEL) && (q->level != r->level)) return 0;
        if ((qtype & ASL_QUERY_MATCH_PID) && (q->pid != r->pid)) return 0;
        if ((qtype & ASL_QUERY_MATCH_SENDER) && (q->sender != r->sender)) return 0;
@@ -913,7 +939,6 @@ asl_mini_memory_match(asl_mini_memory_t *s, aslresponse query, aslresponse *res,
        if (s == NULL) return ASL_STATUS_INVALID_STORE;
        if (res == NULL) return ASL_STATUS_INVALID_ARG;
 
-       do_match = 1;
        qp = NULL;
        qtype = NULL;
        rescount = 0;
index b1e6b3bf52efaff1fc9407d5cbb3e3e864dcd099..e727223b2156f9e4111e8fa38f9185c6b57e0c22 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -21,8 +21,8 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#ifndef __asl_mini_memory_H__
-#define __asl_mini_memory_H__
+#ifndef __ASL_MINI_MEMORY_H__
+#define __ASL_MINI_MEMORY_H__
 #include <stdint.h>
 #include <asl.h>
 
@@ -40,6 +40,7 @@ typedef struct
 {
        uint32_t mid;
        uint64_t time;
+       uint32_t nano;
        uint8_t level;
        uint8_t flags;
        uint32_t pid;
@@ -72,4 +73,4 @@ uint32_t asl_mini_memory_fetch(asl_mini_memory_t *s, uint64_t mid, aslmsg *msg);
 
 uint32_t asl_mini_memory_match(asl_mini_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction);
 
-#endif __asl_mini_memory_H__
+#endif /* __ASL_MINI_MEMORY_H__ */
index a524421bf214a9221efd9f1f91e9dc69e8489fe8..b85fc93fd01844c2c8da75fdce175aad5aff7ff5 100644 (file)
@@ -402,6 +402,7 @@ get_line_from_file(FILE *f)
 
        memcpy(s, out, len);
 
+       if (s[len - 1] != '\n') len++;
        s[len - 1] = '\0';
        return s;
 }
index 4ad9a6ada0b5015f7dda99c62e1891337bca5957..a8a52d188c0b5a5f169d5447520ea137b0be51fc 100644 (file)
@@ -3,7 +3,7 @@
        archiveVersion = 1;
        classes = {
        };
-       objectVersion = 45;
+       objectVersion = 46;
        objects = {
 
 /* Begin PBXAggregateTarget section */
@@ -29,7 +29,6 @@
                5020A3821098EEFD00982ED6 /* System.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5020A3811098EEFD00982ED6 /* System.framework */; };
                5039176F1091408B0001165E /* aslmanager.c in Sources */ = {isa = PBXBuildFile; fileRef = 5039176C1091408B0001165E /* aslmanager.c */; };
                503917B81091410E0001165E /* asl_action.c in Sources */ = {isa = PBXBuildFile; fileRef = 503917A61091410E0001165E /* asl_action.c */; };
-               503917B91091410E0001165E /* asl_in.c in Sources */ = {isa = PBXBuildFile; fileRef = 503917A71091410E0001165E /* asl_in.c */; };
                503917BA1091410E0001165E /* bb_convert.c in Sources */ = {isa = PBXBuildFile; fileRef = 503917A91091410E0001165E /* bb_convert.c */; };
                503917BB1091410E0001165E /* bsd_in.c in Sources */ = {isa = PBXBuildFile; fileRef = 503917AA1091410E0001165E /* bsd_in.c */; };
                503917BC1091410E0001165E /* bsd_out.c in Sources */ = {isa = PBXBuildFile; fileRef = 503917AB1091410E0001165E /* bsd_out.c */; };
                5039176D1091408B0001165E /* com.apple.aslmanager.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.aslmanager.plist; path = aslmanager.tproj/com.apple.aslmanager.plist; sourceTree = "<group>"; };
                5039177C109140C30001165E /* syslogd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = syslogd; sourceTree = BUILT_PRODUCTS_DIR; };
                503917A61091410E0001165E /* asl_action.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = asl_action.c; path = syslogd.tproj/asl_action.c; sourceTree = "<group>"; };
-               503917A71091410E0001165E /* asl_in.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = asl_in.c; path = syslogd.tproj/asl_in.c; sourceTree = "<group>"; };
                503917A81091410E0001165E /* asl.conf.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = asl.conf.5; path = syslogd.tproj/asl.conf.5; sourceTree = "<group>"; };
                503917A91091410E0001165E /* bb_convert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bb_convert.c; path = syslogd.tproj/bb_convert.c; sourceTree = "<group>"; };
                503917AA1091410E0001165E /* bsd_in.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bsd_in.c; path = syslogd.tproj/bsd_in.c; sourceTree = "<group>"; };
                        children = (
                                503917A61091410E0001165E /* asl_action.c */,
                                2DB4DA0A125FC69A001CDC45 /* after_install.sh */,
-                               503917A71091410E0001165E /* asl_in.c */,
                                503917A81091410E0001165E /* asl.conf.5 */,
                                503917A91091410E0001165E /* bb_convert.c */,
                                503917AA1091410E0001165E /* bsd_in.c */,
 /* Begin PBXProject section */
                08FB7793FE84155DC02AAC07 /* Project object */ = {
                        isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 0440;
+                       };
                        buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "syslog" */;
-                       compatibilityVersion = "Xcode 3.1";
+                       compatibilityVersion = "Xcode 3.2";
                        developmentRegion = English;
                        hasScannedForEncodings = 1;
                        knownRegions = (
                        buildActionMask = 2147483647;
                        files = (
                                503917B81091410E0001165E /* asl_action.c in Sources */,
-                               503917B91091410E0001165E /* asl_in.c in Sources */,
                                503917BA1091410E0001165E /* bb_convert.c in Sources */,
                                503917BB1091410E0001165E /* bsd_in.c in Sources */,
                                503917BC1091410E0001165E /* bsd_out.c in Sources */,
                                GCC_PREFIX_HEADER = "";
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
-                               PREBINDING = NO;
                                USE_HEADERMAP = NO;
                                VERSIONING_SYSTEM = "apple-generic";
                                ZERO_LINK = NO;
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                PRODUCT_NAME = All;
                                ZERO_LINK = NO;
                        };
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                INSTALL_PATH = /usr/sbin;
                                OTHER_CFLAGS = (
                                        "-Wall",
                                        "-DINET6",
                                );
-                               PREBINDING = NO;
                                PRODUCT_NAME = aslmanager;
                                ZERO_LINK = NO;
                        };
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                HEADER_SEARCH_PATHS = (
                                        "$(BUILT_PRODUCTS_DIR)/$(CURRENT_ARCH)",
                                        "$(PROJECT_DIR)/aslcommon",
                                        "-DCONFIG_MAC",
                                        "-DREMOTE_IPV4",
                                );
-                               PREBINDING = NO;
                                PRODUCT_NAME = syslogd;
                                ZERO_LINK = NO;
                        };
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                HEADER_SEARCH_PATHS = (
                                        "$(BUILT_PRODUCTS_DIR)/$(CURRENT_ARCH)",
                                        "$(PROJECT_DIR)/aslcommon",
                                        "$(OTHER_CFLAGS)",
                                        "-DCONFIG_IPHONE",
                                );
-                               PREBINDING = NO;
                                PRODUCT_NAME = syslog;
                                ZERO_LINK = NO;
                        };
                                CODE_SIGN_IDENTITY = "-";
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/aslcommon";
                                INSTALL_PATH = /usr/local/lib;
                                OTHER_CFLAGS = (
                                        "-Wall",
                                        "-D__MigTypeCheck=1",
                                );
-                               PREBINDING = NO;
                                PRODUCT_NAME = aslcommon;
                                ZERO_LINK = NO;
                        };
index eb07c3c3bed29afed375e86710be4e56aaa5ae2a..190f6eb0a51fe9960ac652fb7ed2c0e306adcad5 100755 (executable)
@@ -1,10 +1,16 @@
 #! /bin/bash
+set -e
 
 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,')
+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
+       PRODUCT=MacOSX
 fi
 
 if [ ${PRODUCT} = iPhone ]; then
@@ -15,6 +21,11 @@ fi
 DESTDIR="$DSTROOT"/System/Library/LaunchDaemons
 install -d -m 0755 -o root -g wheel "$DESTDIR"
 install -m 0644 -o root -g wheel "$SRCROOT"/syslogd.tproj/com.apple.syslogd.plist "$DESTDIR"
+if [ ${PRODUCT} = iPhoneOS ]; then
+       /usr/libexec/PlistBuddy \
+               -c "Add :POSIXSpawnType string Interactive" \
+               "$DESTDIR"/com.apple.syslogd.plist
+fi
 plutil -convert binary1 "$DESTDIR"/com.apple.syslogd.plist
 
 mkfile 8 "$DSTROOT"/private/var/log/asl/SweepStore
index 1b859c4172d04f44f57e6907ba42c51d7b23d8c3..8d305ac224e16bb80f83f3a691fe23b69f52b199 100644 (file)
@@ -1,4 +1,4 @@
-.\"Copyright (c) 2004-2009 Apple Inc. All rights reserved.
+.\"Copyright (c) 2004-2011 Apple Inc. All rights reserved.
 .\"
 .\"@APPLE_LICENSE_HEADER_START@
 .\"
@@ -44,7 +44,8 @@ and may contain query-action rules that trigger specific actions when
 .Nm syslogd
 receives messages that match the query pattern.
 .Pp
-Parameter setting lines in the configuration file begin with an equal sign ("="), 
+Parameter setting lines in the configuration file begin with an equal sign
+.Dq = , 
 and are generally of the form:
 .Pp
 .Dl = parameter_name value ...
@@ -52,7 +53,9 @@ and are generally of the form:
 Most parameter settings require a single value, although some may take several values.
 See the PARAMETER SETTINGS section below for details.
 .Pp
-Query-action rules in the file begin with a question-mark ("?") or a "Q", and generally have the form:
+Query-action rules in the file begin with a question-mark ``?'' or a
+.Dq Q ,
+and generally have the form:
 .Pp
 .Dl ? query action ...
 .Pp
@@ -66,35 +69,32 @@ The following parameter-settings are recognized by
 .It debug
 Enables or disables internal debugging output.
 This is probably of little interest to most users.
-The debug parameter requires a value of "1" to enable debug output, or a value of "0" to disable it.
-An option file name may follow the "0" or "1".
+The debug parameter requires a value of
+.Dq 1
+to enable debug output, or a value of
+.Dq 0
+to disable it.
+An option file name may follow the
+.Dq 0
+or
+.Dq 1 .
 If a file name is provided, debug messages are written to that file.
 Otherwise, debug writes are treated as log messages.
 .Pp
-.It cutoff
-Sets the ASL data store cutoff level, given as an integer in the range 0 to 7 as an argument.
-The cutoff level is 7 by default, allowing any message that matches a "store" action
-(see QUERY-ACTION RULES below) to be saved.
-Setting the cutoff to a lower value will prevent messages with log priority levels numerically
-greater that the specified cutoff from being saved in the ASL data store.
-.Pp
 .It mark_time
 Sets the time interval for the mark facility.
 The default is 0 seconds, which indicates that mark messages are not generated.
 .Pp
 .It dup_delay
-Sets the maximum time that the bsd_out module will allow before writing a "last message repeated <N> times"
-message in a log file specified in /etc/syslog.conf.
+Sets the maximum time before writing a
+.Dq "last message repeated <N> times"
+message in a log file when duplicate messages have been detected.
 The default is 30 seconds.
 .Pp
 .It utmp_ttl
 Sets the time-to-live for messages used by the utmp, wtmp, and lastlog subsystems.
 The default is 31622400 seconds (approximately 1 year).
 .Pp
-.It fs_ttl
-Sets the time-to-live for filesystem error messages generated by the kernel.
-The default is 31622400 seconds (approximately 1 year).
-.Pp
 .It mps_limit
 Sets the per-process message per second quota.
 The default is value is 500.
@@ -156,32 +156,52 @@ For example
 .Pp
 .Dl [= Sender foobar]
 .Pp
-matches any message with key="Sender" and val="foobar".
+matches any message with value 
+.Dq foobar
+for the 
+.Dq Sender
+key.
 The query
 .Pp
 .Dl [CA= Color gr]
 .Pp
-matches any message with key=Color and val beginning with the letters GR, Gr, gr, or gR
-(C meaning casefold, A meaning prefix).
+matches any message with a value beginning with the letters GR, Gr, gr, or gR
+(C meaning casefold, A meaning prefix) for the
+.Dq Color
+key.
 The example query above,
 .Pp
 .Dl [= Sender foobar] [N< Level 3]
 .Pp
-matches any message from "foobar" with a level numerically less than 3
+matches any message from 
+.Dq foobar
+with a level numerically less than 3
 (string values are converted to integers, and the comparison is done on the integer values).
 Note that the string values may be used equivalently for the Level key,
 so the example above may also be written as:
 .Pp
 .Dl [= Sender foobar] [< Level Error]
 .Pp
-String values for levels may be any of the set "emergency", "alert", "critical", "error",
-"warning", "notice", "info", or "debug".  These strings may be upper, lower, or mixed case.
+String values for levels may be any of the set
+.Dq emergency ,
+.Dq alert ,
+.Dq critical ,
+.Dq error ,
+.Dq warning ,
+.Dq notice ,
+.Dq info , or
+.Dq debug .
+These strings may be upper, lower, or mixed case.
 .Pp
-The "T" operator is useful to test for the presence of a particular key.
+The
+.Dq T
+operator is useful to test for the presence of a particular key.
 .Pp
 .Dl [T Flavor]
 .Pp
-Will match any message that has a "Flavor" key, regardless of its value.
+Will match any message that has a
+.Dq Flavor
+key, regardless of its value.
 .Pp
 .Ss Actions
 The following actions are available.
@@ -192,13 +212,17 @@ Causes
 .Nm syslogd
 to post a notification with
 .Fn notify_post .
-The notification key must appear as a single parameter following the "notify" action.
+The notification key must appear as a single parameter following the
+.Dq notify
+action.
 .Pp
 .It access
 Sets read access controls for messages that match the associated query pattern. 
 .Nm syslogd
 will restrict read access to matching messages to a specific user and group.
-The user ID number and group ID number must follow the "access" keyword as parameters.
+The user ID number and group ID number must follow the
+.Dq access
+keyword as parameters.
 .Pp
 .It store
 Causes
@@ -210,19 +234,29 @@ A separate data store file may be accessed using the
 command line utility.
 A new file will be created if one does not exist.
 If a new file is being created, the UID, GID, and mode of the file may be specified using the options
-"uid=UUU", "gid=GGG", and "mode=MMMM", where UUU and GGG are a user ID and group ID, and MMMM is a 
-mode specification of the form "0644" (for an octal number) or DDD for a decimal number.
+.Dq uid=UUU ,
+.Dq gid=GGG ,
+and
+.Dq mode=MMMM ,
+where UUU and GGG are a user ID and group ID, and MMMM is a 
+mode specification of the form
+.Dq 0644
+with a leading zero for an octal number or DDD for a decimal number.
 .Pp
 Two other optional parameters may also follow the pathname.
 .Pp
 If a separate log message data store file is specified as a parameter, then
 .Nm syslogd
 will open the database, save a matching message, and then close the database.
-If a high volume of messages is expected, specifying the "stayopen" option will improve performance.
+If a high volume of messages is expected, specifying the
+.Dq stayopen
+option will improve performance.
 .Pp
 Also, if a separate log message data store file is specified as a parameter,
 matching messages will be excluded from all further processing.
-Adding the "continue" option will cause syslogd to save matching messages in the specified store file
+Adding the
+.Dq continue
+option will cause syslogd to save matching messages in the specified store file
 and then continue processing matching messages in accordance with the actions
 specified in /etc/asl.conf and /etc/syslog.conf.
 .Pp
@@ -230,7 +264,7 @@ Note that if the
 .Nm asl.conf
 configuration file contains no matching rules for the main ASL data store, then
 .Nm syslogd
-will save all messages, subject to filtering in accordance with the log cutoff level.
+will save all messages.
 .Pp
 .It store_directory
 Causes matching messages to be stored in a log message data store file in a separate directory.
@@ -239,18 +273,111 @@ The named directory must exist.
 .Nm syslogd
 will not create the directory path.
 .Pp
-Messages saved to a store directory are saved in files that are named "yyyy.mm.dd.asl",
-where "yyyy", "mm", and "dd" are the year, month (01 to 12) and day of the month (01 to 31) associated with
+Messages saved to a store directory are saved in files that are named
+.Dq yyyy.mm.dd.asl ,
+where 
+.Dq yyyy ,
+.Dq mm ,
+and
+.Dq dd
+are the year, month (01 to 12) and day of the month (01 to 31) associated with
 matching messages.
 This has the effect of saving messages in a separate file for each day.
 .Pp
-The "uid=UUU", "gid=GGG", "mode=MMMM", and "continue" options available for the "store" action
+The
+.Dq uid=UUU ,
+.Dq gid=GGG ,
+.Dq mode=MMMM ,
+and
+.Dq continue
+options available for the
+.Dq store
+action
 may also be specified for a store directory.
 The uid, gid, and mode specification will be used when the individual daily store files are created.
 .Pp
+.It file
+Causes matching messages to be stored in a log file.
+The file's path name must follow as the first parameter.
+The file's directory must exist.
+If the path already exists, it must be a plain file.
+Otherwise
+.Nm syslogd
+will create the file.
+The file's owner will be root, and the file's group will be admin.
+A file mode may be specified as an option of the form 
+.Dq mode=MMMM
+as described above.
+One or more UIDs may be given as the values of options of the form 
+.Dq uid=UUU .
+One or more GIDs may be given as the values of options of the form 
+.Dq gid=GGG .
+If any UIDs or GIDs are provided, the specified users and groups will be given read access to the file.
+Note that UIDs and GIDs should be defined in the local Open Directory database, since
+.Nm syslogd
+starts and may create the log file before network directory services are available.
+Unknown UIDs and GIDs will be ignored when setting access controls.
+.Pp
+By default, log files will be written using the same format used for printing by 
+.Nm syslog
+when the
+.Fl F Ar std
+flag is supplied.
+A print format may be specified as the value of the
+.Dq format=FMT
+option.
+The default is
+.Dq format=std .
+Alternate file formats, including
+.Dq bsd
+and
+.Dq raw
+are supported.
+Custom formats may be specified as well, using the syntax supported by
+.Nm syslog Fl F .
+Space and tab character in a custom format string must be escaped with a leading backslash character.
+Custom format strings may include variables of the form
+.Dq $Name
+.Dq $(Name)
+or
+.Dq $((Name)(fmt)) .
+which will be expanded to the associated with the named key.
+The first form may be used in most cases.
+The second form may be used if the variable is not delimited by whitespace.
+The third form permits the selection of alternate output formats for certain keys,
+such as Time and Level.
+See
+.Xr syslog 1
+for details.
+.Pp
+For example, the option:
+.Pp
+.Dl format=$((Time)(Z))\ $Host\ $(Sender)[$(PID)]\ <$((Level)(str))>:\ $Message
+.Pp
+produces output similar to the 
+.Dq std
+format, but using the UTC (Zulu) timezone.
+.Pp
+By default, files printed using the
+.Dq bsd
+and
+.Dq std
+formats will suppress printing duplicates.
+If two or more messages are logged within 30 seconds, and which differ only in time,
+then the second and subsequent messages will not be printed.
+When a different message is logged, or 30 seconds have elapsed since the initial
+message was logged, a line with the text
+.Dl --- last message repeated N times ---
+will be added to the file.
+The default may be disabled using the 
+.Dq no_dup_supress
+option.
+.Pp
 .It broadcast
 Causes syslogd to write the text of matching messages to all terminal windows.
-If optional text follows the "broadcast" keyword, then  that text is written rather that the matching message text.
+If optional text follows the
+.Dq broadcast
+keyword, then that text is written rather that the matching message text.
 .Pp
 .It ignore
 Causes a matching message to be ignored in all subsequent matching rules.
@@ -263,7 +390,11 @@ The following parameter-settings are recognized by
 .It aslmanager_debug
 Enables or disables internal debugging output.
 This is probably of little interest to most users.
-The debug parameter requires a value of "1" to enable debug output, or a value of "0" to disable it.
+The debug parameter requires a value of 
+.Dq 1
+to enable debug output, or a value of 
+.Dq 0
+to disable it.
 Debug messages are sent to
 .Nm syslogd .
 .Pp
@@ -277,8 +408,15 @@ The default is 150000000 bytes.
 .Pp
 .It archive
 Enables or disables archiving.
-The archive parameter requires a value of "1" to enable archiving, or a value of "0" to disable it.
-An option archive directory path may follow the "0" or "1".
+The archive parameter requires a value of 
+.Dq 1
+to enable archiving, or a value of
+.Dq 0
+to disable it.
+An option archive directory path may follow the
+.Dq 0
+or
+.Dq 1 .
 If enabled, files removed from the ASL data store are moved to the archive directory.
 The default archive directory path is /var/log/asl.archive.
 .Pp
index 572f67ba883d2b8fcdf1bbd7d130b8a957d263c8..2848271154d14250b5bed503fc8bea1fc71c4378 100644 (file)
@@ -2,14 +2,14 @@
  * Copyright (c) 2004-2011 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 <netdb.h>
 #include <notify.h>
 #include <pthread.h>
-#include <asl_core.h>
+#include <sys/acl.h>
+#include <membership.h>
 #include "daemon.h"
+#include <dispatch/private.h>
 
 #define _PATH_WALL "/usr/bin/wall"
 #define _PATH_ASL_CONF "/etc/asl.conf"
 #define MY_ID "asl_action"
 
+#define MAX_FAILURES 5
+
 #define ACTION_NONE      0
 #define ACTION_IGNORE    1
 #define ACTION_NOTIFY    2
 #define ACTION_BROADCAST 3
 #define ACTION_ACCESS    4
-#define ACTION_STORE     5
-#define ACTION_STORE_DIR 6
-#define ACTION_FORWARD   7
+#define ACTION_ASL_STORE 5 /* Save in main ASL Database */
+#define ACTION_ASL_FILE  6 /* Save in an ASL format data file */
+#define ACTION_ASL_DIR   7 /* Save in an ASL directory */
+#define ACTION_FILE      8
+#define ACTION_FORWARD   9
 
 #define forever for(;;)
 
+#define ACT_FLAG_HAS_LOGGED   0x80000000
+#define ACT_FLAG_CLEAR_LOGGED 0x7fffffff
+
 #define ACT_STORE_FLAG_STAY_OPEN 0x00000001
 #define ACT_STORE_FLAG_CONTINUE  0x00000002
 
-static asl_msg_t *query = NULL;
-static int reset = RESET_NONE;
-static pthread_mutex_t reset_lock = PTHREAD_MUTEX_INITIALIZER;
+#define ACT_FILE_FLAG_DUP_SUPRESS 0x00000001
+#define ACT_FILE_FLAG_ROTATE      0x00000002
+
+static dispatch_queue_t asl_action_queue;
+static time_t last_file_day;
 
 typedef struct action_rule_s
 {
@@ -79,20 +90,48 @@ struct store_data
        uid_t uid;
        gid_t gid;
        uint64_t next_id;
+       uint32_t fails;
        uint32_t flags;
+       uint32_t refcount;
        uint32_t p_year;
        uint32_t p_month;
        uint32_t p_day;
 };
 
+struct file_data
+{
+       int fd;
+       char *path;
+       char *fmt;
+       const char *tfmt;
+       mode_t mode;
+       uid_t *uid;
+       uint32_t nuid;
+       gid_t *gid;
+       uint32_t ngid;
+       size_t max_size;
+       uint32_t fails;
+       uint32_t flags;
+       uint32_t refcount;
+       time_t stamp;
+       uint32_t last_hash;
+       uint32_t last_count;
+       time_t last_time;
+       dispatch_source_t dup_timer;
+       char *last_msg;
+};
+
 static action_rule_t *asl_action_rule = NULL;
 static action_rule_t *asl_datastore_rule = NULL;
-static int filter_token = -1;
 
-int asl_action_close();
 static int _parse_config_file(const char *);
 extern void db_save_message(aslmsg m);
 
+/* forward */
+int _act_file_open(struct file_data *fdata);
+static void _act_file_init(action_rule_t *r);
+static void _act_store_init(action_rule_t *r);
+
 static char *
 _next_word(char **s)
 {
@@ -155,30 +194,14 @@ _next_word(char **s)
        return out;
 }
 
-static void
-_do_reset(void)
-{
-       pthread_mutex_lock(&reset_lock);
-
-       if (reset == RESET_CONFIG)
-       {
-               asl_action_close();
-               _parse_config_file(_PATH_ASL_CONF);
-       }
-
-       reset = RESET_NONE;
-
-       pthread_mutex_unlock(&reset_lock);
-}
-
 /*
  * Config File format:
  * Set parameter rule - initializes a parameter.
  *             = param args...
  * Query rule - if a message matches the query, then the action is invoked.
  * The rule may be identified by either "?" or "Q".
- *             ? [k v] [k v] ... action args...   
- *             Q [k v] [k v] ... action args...   
+ *             ? [k v] [k v] ... action args...
+ *             Q [k v] [k v] ... action args...
  * Universal match rule - the action is invoked for all messages
  *             * action args...
  */
@@ -239,10 +262,12 @@ _parse_query_action(char *s)
        else if (!strcasecmp(act, "notify"))          out->action = ACTION_NOTIFY;
        else if (!strcasecmp(act, "broadcast"))       out->action = ACTION_BROADCAST;
        else if (!strcasecmp(act, "access"))          out->action = ACTION_ACCESS;
-       else if (!strcasecmp(act, "store"))           out->action = ACTION_STORE;
-       else if (!strcasecmp(act, "save"))            out->action = ACTION_STORE;
-       else if (!strcasecmp(act, "store_directory")) out->action = ACTION_STORE_DIR;
-       else if (!strcasecmp(act, "store_dir"))       out->action = ACTION_STORE_DIR;
+       else if (!strcasecmp(act, "store"))           out->action = ACTION_ASL_STORE;
+       else if (!strcasecmp(act, "save"))            out->action = ACTION_ASL_STORE;
+       else if (!strcasecmp(act, "store_file"))      out->action = ACTION_ASL_FILE;
+       else if (!strcasecmp(act, "store_directory")) out->action = ACTION_ASL_DIR;
+       else if (!strcasecmp(act, "store_dir"))       out->action = ACTION_ASL_DIR;
+       else if (!strcasecmp(act, "file"))            out->action = ACTION_FILE;
        else if (!strcasecmp(act, "forward"))         out->action = ACTION_FORWARD;
 
        if (p != NULL)
@@ -275,9 +300,15 @@ _parse_query_action(char *s)
                return -1;
        }
 
-       if ((out->action == ACTION_STORE) && (out->options == NULL))
+       /* store /some/path means save to a file */
+       if ((out->action == ACTION_ASL_STORE) && (out->options != NULL)) out->action = ACTION_ASL_FILE;
+
+       if (out->action == ACTION_FILE) _act_file_init(out);
+       else if ((out->action == ACTION_ASL_FILE) || (out->action == ACTION_ASL_DIR)) _act_store_init(out);
+
+       if (out->action == ACTION_ASL_STORE)
        {
-               asldebug("action = ACTION_STORE options = NULL\n");
+               asldebug("action = ACTION_ASL_STORE\n");
                if (asl_datastore_rule == NULL) asl_datastore_rule = out;
                else
                {
@@ -299,160 +330,6 @@ _parse_query_action(char *s)
        return 0;
 }
 
-/*
- * Used to sed config parameters.
- * Line format "= name value"
- */
-static int
-_parse_set_param(char *s)
-{
-       char **l;
-       uint32_t intval, count, v32a, v32b, v32c;
-
-       if (s == NULL) return -1;
-       if (s[0] == '\0') return 0;
-
-       /* skip '=' and whitespace */
-       s++;
-       while ((*s == ' ') || (*s == '\t')) s++;
-
-       l = explode(s, " \t");
-       if (l == NULL) return -1;
-
-       for (count = 0; l[count] != NULL; count++);
-
-       /* name is required */
-       if (count == 0)
-       {
-               freeList(l);
-               return -1;
-       }
-
-       /* value is required */
-       if (count == 1)
-       {
-               freeList(l);
-               return -1;
-       }
-
-       if (!strcasecmp(l[0], "debug"))
-       {
-               /* = debug {0|1} [file] */
-               intval = atoi(l[1]);
-               config_debug(intval, l[2]);
-       }
-       else if (!strcasecmp(l[0], "cutoff"))
-       {
-               /* = cutoff level */
-               intval = atoi(l[1]);
-               if (intval > ASL_LEVEL_DEBUG) intval = ASL_LEVEL_DEBUG;
-               global.asl_log_filter = ASL_FILTER_MASK_UPTO(intval);
-       }
-       else if (!strcasecmp(l[0], "mark_time"))
-       {
-               /* = mark_time seconds */
-               OSSpinLockLock(&global.lock);
-               global.mark_time = atoll(l[1]);
-               OSSpinLockUnlock(&global.lock);
-       }
-       else if (!strcasecmp(l[0], "dup_delay"))
-       {
-               /* = bsd_max_dup_time seconds */
-               OSSpinLockLock(&global.lock);
-               global.bsd_max_dup_time = atoll(l[1]);
-               OSSpinLockUnlock(&global.lock);
-       }
-       else if (!strcasecmp(l[0], "asl_store_ping_time"))
-       {
-               /* NB this is private / unpublished */
-               /* = asl_store_ping_time seconds */
-               OSSpinLockLock(&global.lock);
-               global.asl_store_ping_time = atoll(l[1]);
-               OSSpinLockUnlock(&global.lock);
-       }
-       else if (!strcasecmp(l[0], "utmp_ttl"))
-       {
-               /* = utmp_ttl seconds */
-               OSSpinLockLock(&global.lock);
-               global.utmp_ttl = (time_t)atoll(l[1]);
-               OSSpinLockUnlock(&global.lock);
-       }
-       else if (!strcasecmp(l[0], "fs_ttl"))
-       {
-               /* = fs_ttl seconds */
-               OSSpinLockLock(&global.lock);
-               global.fs_ttl = (time_t)atoll(l[1]);
-               OSSpinLockUnlock(&global.lock);
-       }
-       else if (!strcasecmp(l[0], "mps_limit"))
-       {
-               /* = mps_limit number */
-               OSSpinLockLock(&global.lock);
-               global.mps_limit = (uint32_t)atol(l[1]);
-               OSSpinLockUnlock(&global.lock);
-       }
-       else if (!strcasecmp(l[0], "max_file_size"))
-       {
-               /* = max_file_size bytes */
-               pthread_mutex_lock(global.db_lock);
-
-               if (global.dbtype & DB_TYPE_FILE)
-               {
-                       asl_store_close(global.file_db);
-                       global.file_db = NULL;
-                       global.db_file_max = atoi(l[1]);
-               }
-
-               pthread_mutex_unlock(global.db_lock);
-       }
-       else if ((!strcasecmp(l[0], "db")) || (!strcasecmp(l[0], "database")) || (!strcasecmp(l[0], "datastore")))
-       {
-               /* NB this is private / unpublished */
-               /* = db type [max]... */
-
-               v32a = 0;
-               v32b = 0;
-               v32c = 0;
-
-               if ((l[1][0] >= '0') && (l[1][0] <= '9'))
-               {
-                       intval = atoi(l[1]);
-                       if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
-                       if ((count >= 4) && (strcmp(l[3], "-"))) v32b = atoi(l[3]);
-                       if ((count >= 5) && (strcmp(l[4], "-"))) v32c = atoi(l[4]);
-               }
-               else if (!strcasecmp(l[1], "file"))
-               {
-                       intval = DB_TYPE_FILE;
-                       if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
-               }
-               else if (!strncasecmp(l[1], "mem", 3))
-               {
-                       intval = DB_TYPE_MEMORY;
-                       if ((count >= 3) && (strcmp(l[2], "-"))) v32b = atoi(l[2]);
-               }
-               else if (!strncasecmp(l[1], "min", 3))
-               {
-                       intval = DB_TYPE_MINI;
-                       if ((count >= 3) && (strcmp(l[2], "-"))) v32c = atoi(l[2]);
-               }
-               else
-               {
-                       freeList(l);
-                       return -1;
-               }
-
-               if (v32a == 0) v32a = global.db_file_max;
-               if (v32b == 0) v32b = global.db_memory_max;
-               if (v32c == 0) v32c = global.db_mini_max;
-
-               config_data_store(intval, v32a, v32b, v32c);
-       }
-
-       freeList(l);
-       return 0;
-}
-
 static int
 _parse_line(char *s)
 {
@@ -482,7 +359,7 @@ _parse_line(char *s)
                case '=':
                {
                        /* Set parameter */
-                       status = _parse_set_param(s);
+                       status = control_set_param(s);
                        break;
                }
                default:
@@ -502,14 +379,14 @@ _parse_line(char *s)
                                 ASL_KEY_MSG, _PATH_ASL_CONF, s,
                                 ASL_KEY_UID, ASL_KEY_GID);
 
-               asl_log_string(str);
+               internal_log_message(str);
                free(str);
        }
 
        return status;
 }
 
-static void 
+static void
 _act_notify(action_rule_t *r)
 {
        if (r == NULL) return;
@@ -619,20 +496,16 @@ _act_store_dir_setup(struct store_data *sd, time_t tick)
                        mask = umask(0);
                        status = mkdir(sd->dir, sd->mode);
                        umask(mask);
-                       
+
                        if (status != 0) return ASL_STATUS_WRITE_FAILED;
-                       
-                       if ((sd->uid != 0) || (sd->gid != 0))
-                       {
-                               if (chown(sd->dir, sd->uid, sd->gid) != 0) return ASL_STATUS_WRITE_FAILED;
-                       }
+                       if (chown(sd->dir, sd->uid, sd->gid) != 0) return ASL_STATUS_WRITE_FAILED;
                }
                else
                {
                        /* Unexpected stat error */
                        return ASL_STATUS_FAILED;
                }
-               
+
                path = NULL;
                asprintf(&path, "%s/%s", sd->dir, FILE_ASL_STORE_DATA);
                if (path == NULL) return ASL_STATUS_NO_MEMORY;
@@ -667,13 +540,10 @@ _act_store_dir_setup(struct store_data *sd, time_t tick)
                                return ASL_STATUS_FAILED;
                        }
 
-                       if ((sd->uid != 0) || (sd->gid != 0))
+                       if (chown(path, sd->uid, sd->gid) != 0)
                        {
-                               if (chown(path, sd->uid, sd->gid) != 0)
-                               {
-                                       free(path);
-                                       return ASL_STATUS_WRITE_FAILED;
-                               }
+                               free(path);
+                               return ASL_STATUS_WRITE_FAILED;
                        }
                }
                else
@@ -741,148 +611,116 @@ _act_store_dir_setup(struct store_data *sd, time_t tick)
 }
 
 static void
-_act_store(action_rule_t *r, aslmsg msg)
+_act_store_init(action_rule_t *r)
 {
-       struct store_data *sd;
-       asl_file_t *s;
-       uint8_t x;
-       uint32_t status;
-       uint64_t mid;
-       mode_t tmp_mode, mask;
-       char *str, *opts, *p;
-       const char *val;
-       time_t tick;
+       struct store_data *sd, *xd;
+       char *str, *opts, *p, *path;
+       action_rule_t *x;
 
-       s = NULL;
+       /* check if the store data is already set up */
+       if (r->data != NULL) return;
 
-       /* _act_store is not used for the main ASL data store */
-       if (r->options == NULL) return;
+       opts = r->options;
+       path = _next_word(&opts);
 
-       if (r->data == NULL)
+       if ((path == NULL) || (path[0] != '/'))
        {
-               /* set up store data */
-               sd = (struct store_data *)calloc(1, sizeof(struct store_data));
-               if (sd == NULL) return;
+               str = NULL;
+               asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [Facility syslog] [%s Invalid path for \"%s\" action: %s]",
+                                ASL_KEY_SENDER,
+                                ASL_KEY_LEVEL, ASL_LEVEL_ERR,
+                                ASL_KEY_PID, getpid(),
+                                ASL_KEY_MSG,
+                                (r->action == ACTION_ASL_FILE) ? "store" : "store_directory",
+                                (path == NULL) ? "no path specified" : path);
 
-               opts = r->options;
-               sd->store = NULL;
+               internal_log_message(str);
+               free(str);
+               r->action = ACTION_NONE;
+               free(path);
+               return;
+       }
 
-               if (r->action == ACTION_STORE)
+       /* check if a previous rule has set up this path (ACTION_ASL_FILE) or dir (ACTION_ASL_DIR) */
+       for (x = asl_action_rule; x != NULL; x = x->next)
+       {
+               if ((x->action == r->action) && (x->data != NULL))
                {
-                       sd->path = _next_word(&opts);
-                       if ((sd->path == NULL) || (sd->path[0] != '/'))
-                       {
-                               str = NULL;
-                               asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [Facility syslog] [%s Invalid path for \"store\" action: %s]",
-                                                ASL_KEY_SENDER,
-                                                ASL_KEY_LEVEL, ASL_LEVEL_ERR,
-                                                ASL_KEY_PID, getpid(),
-                                                ASL_KEY_MSG, (sd->path == NULL) ? "no path specified" : sd->path);
+                       xd = (struct store_data *)x->data;
+                       p = xd->path;
+                       if (r->action == ACTION_ASL_DIR) p = xd->dir;
 
-                               asl_log_string(str);
-                               free(str);
-                               free(sd);
-                               r->action = ACTION_NONE;
-                               return;
-                       }
-               }
-               else if (r->action == ACTION_STORE_DIR)
-               {
-                       sd->dir = _next_word(&opts);
-                       if ((sd->dir == NULL) || (sd->dir[0] != '/'))
+                       if ((p != NULL) && (!strcmp(path, p)))
                        {
-                               str = NULL;
-                               asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [Facility syslog] [%s Invalid path for \"store_directory\" action: %s]",
-                                                ASL_KEY_SENDER,
-                                                ASL_KEY_LEVEL, ASL_LEVEL_ERR,
-                                                ASL_KEY_PID, getpid(),
-                                                ASL_KEY_MSG, (sd->dir == NULL) ? "no path specified" : sd->dir);
-
-                               asl_log_string(str);
-                               free(str);
-                               free(sd);
-                               r->action = ACTION_NONE;
+                               free(path);
+                               xd->refcount++;
+                               r->data = x->data;
                                return;
                        }
                }
+       }
+
+       /* set up store data */
+       sd = (struct store_data *)calloc(1, sizeof(struct store_data));
+       if (sd == NULL) return;
 
-               sd->mode = 0755;
-               sd->next_id = 0;
-               sd->uid = 0;
-               sd->gid = 0;
-               sd->flags = 0;
+       sd->refcount = 1;
+       sd->mode = 0755;
+       sd->next_id = 0;
+       sd->uid = 0;
+       sd->gid = 0;
+       sd->flags = 0;
 
-               while (NULL != (p = _next_word(&opts)))
+       if (r->action == ACTION_ASL_DIR) sd->dir = path;
+       else sd->path = path;
+
+       while (NULL != (p = _next_word(&opts)))
+       {
+               if (!strcmp(p, "stayopen"))
                {
-                       if (!strcmp(p, "stayopen"))
-                       {
-                               sd->flags |= ACT_STORE_FLAG_STAY_OPEN;
-                       }
-                       else if (!strcmp(p, "continue"))
-                       {
-                               sd->flags |= ACT_STORE_FLAG_CONTINUE;
-                       }
-                       else if (!strncmp(p, "mode=0", 6))
-                       {
-                               sd->mode = 0;
-                               x = *(p + 6);
-                               if ((x < '0') || (x > '7'))
-                               {
-                                       free(p);
-                                       free(sd->path);
-                                       free(sd->dir);
-                                       free(sd);
-                                       r->action = ACTION_NONE;
-                                       return;
-                               }
+                       sd->flags |= ACT_STORE_FLAG_STAY_OPEN;
+               }
+               else if (!strcmp(p, "continue"))
+               {
+                       sd->flags |= ACT_STORE_FLAG_CONTINUE;
+               }
+               else if (!strncmp(p, "mode=", 5)) sd->mode = strtol(p+5, NULL, 0);
+               else if (!strncmp(p, "uid=", 4)) sd->uid = atoi(p+4);
+               else if (!strncmp(p, "gid=", 4)) sd->gid = atoi(p+4);
 
-                               tmp_mode = x - '0';
-                               sd->mode += tmp_mode << 6;
+               free(p);
+               p = NULL;
+       }
 
-                               x = *(p + 7);
-                               if ((x < '0') || (x > '7'))
-                               {
-                                       free(p);
-                                       free(sd->path);
-                                       free(sd->dir);
-                                       free(sd);
-                                       r->action = ACTION_NONE;
-                                       return;
-                               }
+       r->data = sd;
+}
 
-                               tmp_mode = x - '0';
-                               sd->mode += tmp_mode << 3;
+/*
+ * Save a message to an ASL format file (ACTION_ASL_FILE)
+ * or to an ASL directory (ACTION_ASL_DIR).
+ */
+static void
+_act_store(action_rule_t *r, aslmsg msg)
+{
+       struct store_data *sd;
+       asl_file_t *s;
+       uint32_t status;
+       uint64_t mid;
+       mode_t mask;
+       char *str, *opts;
+       const char *val;
+       time_t tick;
 
-                               x = *(p + 8);
-                               if ((x < '0') || (x > '7'))
-                               {
-                                       free(p);
-                                       free(sd->path);
-                                       free(sd->dir);
-                                       free(sd);
-                                       r->action = ACTION_NONE;
-                                       return;
-                               }
+       s = NULL;
 
-                               tmp_mode = x - '0';
-                               sd->mode += tmp_mode;
-                       }
-                       else if (!strncmp(p, "mode=", 5)) sd->mode = atoi(p+4);
-                       else if (!strncmp(p, "uid=", 4)) sd->uid = atoi(p+4);
-                       else if (!strncmp(p, "gid=", 4)) sd->gid = atoi(p+4);
+       if (r->data == NULL) return;
 
-                       free(p);
-                       p = NULL;
-               }
+       sd = (struct store_data *)r->data;
 
-               r->data = sd;
-       }
-       else
-       {
-               sd = (struct store_data *)r->data;
-       }
+       if (sd->flags & ACT_FLAG_HAS_LOGGED) return;
+       sd->flags |= ACT_FLAG_HAS_LOGGED;
 
-       if (r->action == ACTION_STORE_DIR)
+       if (r->action == ACTION_ASL_DIR)
        {
                val = asl_get(msg, ASL_KEY_TIME);
                if (val == NULL) return;
@@ -893,11 +731,30 @@ _act_store(action_rule_t *r, aslmsg msg)
                {
                        asldebug("_act_store_dir_setup %s failed: %s\n", sd->path, asl_core_error(status));
 
-                       /* disable further activity */
-                       asl_file_close(sd->store);
-                       sd->store = NULL;
-                       r->action = ACTION_NONE;
-                       return;
+                       sd->fails++;
+
+                       /* disable further activity after multiple failures */
+                       if (sd->fails > MAX_FAILURES)
+                       {
+                               char *str = NULL;
+                               asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [Facility syslog] [%s Disabling writes to path %s following %u failures (%s)]",
+                                                ASL_KEY_SENDER,
+                                                ASL_KEY_LEVEL, ASL_LEVEL_ERR,
+                                                ASL_KEY_PID, getpid(),
+                                                ASL_KEY_MSG, sd->path, sd->fails, asl_core_error(status));
+
+                               internal_log_message(str);
+                               free(str);
+
+                               asl_file_close(sd->store);
+                               sd->store = NULL;
+                               r->action = ACTION_NONE;
+                               return;
+                       }
+               }
+               else
+               {
+                       sd->fails = 0;
                }
        }
 
@@ -913,28 +770,66 @@ _act_store(action_rule_t *r, aslmsg msg)
                {
                        asldebug("asl_file_open_write %s failed: %s\n", sd->path, asl_core_error(status));
 
-                       /* disable further activity */
-                       asl_file_close(sd->store);
-                       sd->store = NULL;
-                       r->action = ACTION_NONE;
-                       return;
+                       sd->fails++;
+
+                       /* disable further activity after multiple failures */
+                       if (sd->fails > MAX_FAILURES)
+                       {
+                               char *str = NULL;
+                               asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [Facility syslog] [%s Disabling writes to path %s following %u failures (%s)]",
+                                                ASL_KEY_SENDER,
+                                                ASL_KEY_LEVEL, ASL_LEVEL_ERR,
+                                                ASL_KEY_PID, getpid(),
+                                                ASL_KEY_MSG, sd->path, sd->fails, asl_core_error(status));
+
+                               internal_log_message(str);
+                               free(str);
+
+                               asl_file_close(sd->store);
+                               sd->store = NULL;
+                               r->action = ACTION_NONE;
+                               return;
+                       }
+               }
+               else if (status == ASL_STATUS_OK)
+               {
+                       sd->fails = 0;
                }
 
                sd->store = s;
        }
 
-       if (r->action != ACTION_STORE_DIR)
+       if (r->action != ACTION_ASL_DIR)
        {
                status = _act_store_file_setup(sd);
                if (status != ASL_STATUS_OK)
                {
                        asldebug("_act_store_file_setup %s failed: %s\n", sd->path, asl_core_error(status));
 
-                       /* disable further activity */
-                       asl_file_close(sd->store);
-                       sd->store = NULL;
-                       r->action = ACTION_NONE;
-                       return;
+                       sd->fails++;
+
+                       /* disable further activity after multiple failures */
+                       if (sd->fails > MAX_FAILURES)
+                       {
+                               char *str = NULL;
+                               asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [Facility syslog] [%s Disabling writes to path %s following %u failures (%s)]",
+                                                ASL_KEY_SENDER,
+                                                ASL_KEY_LEVEL, ASL_LEVEL_ERR,
+                                                ASL_KEY_PID, getpid(),
+                                                ASL_KEY_MSG, sd->path, sd->fails, asl_core_error(status));
+
+                               internal_log_message(str);
+                               free(str);
+
+                               asl_file_close(sd->store);
+                               sd->store = NULL;
+                               r->action = ACTION_NONE;
+                               return;
+                       }
+               }
+               else
+               {
+                       sd->fails = 0;
                }
        }
 
@@ -945,11 +840,30 @@ _act_store(action_rule_t *r, aslmsg msg)
        {
                asldebug("asl_file_save %s failed: %s\n", sd->path, asl_core_error(status));
 
-               /* disable further activity on this file */
-               asl_file_close(sd->store);
-               sd->store = NULL;
-               r->action = ACTION_NONE;
-               return;
+               sd->fails++;
+
+               /* disable further activity after multiple failures */
+               if (sd->fails > MAX_FAILURES)
+               {
+                       char *str = NULL;
+                       asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [Facility syslog] [%s Disabling writes to path %s following %u failures (%s)]",
+                                        ASL_KEY_SENDER,
+                                        ASL_KEY_LEVEL, ASL_LEVEL_ERR,
+                                        ASL_KEY_PID, getpid(),
+                                        ASL_KEY_MSG, sd->path, sd->fails, asl_core_error(status));
+
+                       internal_log_message(str);
+                       free(str);
+
+                       asl_file_close(sd->store);
+                       sd->store = NULL;
+                       r->action = ACTION_NONE;
+                       return;
+               }
+       }
+       else
+       {
+               sd->fails = 0;
        }
 
        if ((sd->flags & ACT_STORE_FLAG_STAY_OPEN) == 0)
@@ -978,79 +892,592 @@ _act_store(action_rule_t *r, aslmsg msg)
        }
 }
 
-static void
-_act_forward(action_rule_t *r, aslmsg msg)
+static int
+_act_file_send_repeat_msg(struct file_data *fdata)
 {
-       /* To do: <rdar://problem/6130747> Add a "forward" action to asl.conf */
-}
+       char vt[32], *msg;
+       int len, status, closeit;
+       time_t now = time(NULL);
 
-static void
-send_to_asl_store(aslmsg msg)
-{
-       const char *vlevel, *val;
-       uint64_t v64;
-       uint32_t status, level, lmask;
-       int x, log_me;
-       action_rule_t *r;
+       if (fdata == NULL) return -1;
+
+       free(fdata->last_msg);
+       fdata->last_msg = NULL;
+
+       if (fdata->last_count == 0) return 0;
+
+       /* stop the timer */
+       dispatch_suspend(fdata->dup_timer);
+
+       memset(vt, 0, sizeof(vt));
+       ctime_r(&now, vt);
+       vt[19] = '\0';
 
-       if (filter_token == -1)
+       msg = NULL;
+       asprintf(&msg, "%s --- last message repeated %u time%s ---\n", vt + 4, fdata->last_count, (fdata->last_count == 1) ? "" : "s");
+       fdata->last_count = 0;
+       if (msg == NULL) return -1;
+
+       closeit = 0;
+       if (fdata->fd < 0)
        {
-               /* set up com.apple.syslog.asl_filter */
-               status = notify_register_check(NOTIFY_SYSTEM_ASL_FILTER, &filter_token);
-               if (status != NOTIFY_STATUS_OK)
+               closeit = 1;
+               fdata->fd = _act_file_open(fdata);
+               if (fdata->fd < 0)
                {
-                       filter_token = -1;
+                       asldebug("%s: error opening for repeat message (%s): %s\n", MY_ID, fdata->path, strerror(errno));
+                       return -1;
+               }
+       }
+
+       len = strlen(msg);
+       status = write(fdata->fd, msg, len);
+       free(msg);
+       if (closeit != 0)
+       {
+               close(fdata->fd);
+               fdata->fd = -1;
+       }
+
+       if ((status < 0) || (status < len))
+       {
+               asldebug("%s: error writing repeat message (%s): %s\n", MY_ID, fdata->path, strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * N.B. This is basic file rotation support.
+ * More rotation options will be added in the future, along
+ * with support in aslmanager for compression and deletion.
+ */
+static void
+_act_file_rotate_file_data(struct file_data *fdata, time_t now)
+{
+       char str[MAXPATHLEN];
+       size_t len;
+       int width;
+
+       if (now == 0) now = time(NULL);
+
+       /* flush duplicates if pending */
+       _act_file_send_repeat_msg(fdata);
+
+       /* sleep to prevent a sub-second rotation */
+       while (now == fdata->stamp)
+       {
+               sleep(1);
+               now = time(NULL);
+       }
+
+       len = strlen(fdata->path);
+       width = len - 4;
+       if ((len > 4) && (!strcasecmp(fdata->path + width, ".log")))
+       {
+               /* ".log" rename: abc.log -> abc.timestamp.log */
+               snprintf(str, sizeof(str), "%.*s.%lu.log", width, fdata->path, fdata->stamp);
+       }
+       else
+       {
+               snprintf(str, sizeof(str), "%s.%lu", fdata->path, fdata->stamp);
+       }
+
+       rename(fdata->path, str);
+
+       fdata->stamp = now;
+}
+
+int
+_act_file_open(struct file_data *fdata)
+{
+       acl_t acl;
+       uuid_t uuid;
+       acl_entry_t entry;
+       acl_permset_t perms;
+       int status;
+       int fd = -1;
+       mode_t mask;
+       struct stat sb;
+       uint32_t i;
+
+       memset(&sb, 0, sizeof(struct stat));
+       status = stat(fdata->path, &sb);
+       if (status == 0)
+       {
+               /* must be a regular file */
+               if (!S_ISREG(sb.st_mode)) return -1;
+
+               /* use st_birthtimespec if stamp is zero */
+               if (fdata->stamp == 0) fdata->stamp = sb.st_birthtimespec.tv_sec;
+
+               /* rotate if over size limit */
+               if ((fdata->max_size > 0) && (sb.st_size > fdata->max_size))
+               {
+                       _act_file_rotate_file_data(fdata, 0);
                }
                else
                {
-                       status = notify_check(filter_token, &x);
-                       if (status == NOTIFY_STATUS_OK)
+                       /* open existing file */
+                       fd = open(fdata->path, O_RDWR | O_APPEND | O_EXCL, 0);
+                       return fd;
+               }
+       }
+       else if (errno != ENOENT)
+       {
+               return -1;
+       }
+
+#if TARGET_OS_EMBEDDED
+       return open(fdata->path, O_RDWR | O_CREAT | O_EXCL, (fdata->mode & 0666));
+#else
+
+       acl = acl_init(1);
+
+       for (i = 0; i < fdata->ngid; i++)
+       {
+               status = mbr_gid_to_uuid(fdata->gid[i], uuid);
+               if (status != 0)
+               {
+                       char *str = NULL;
+                       asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [Facility syslog] [%s Unknown GID %d for \"file\" action: %s]",
+                                        ASL_KEY_SENDER,
+                                        ASL_KEY_LEVEL, ASL_LEVEL_ERR,
+                                        ASL_KEY_PID, getpid(),
+                                        ASL_KEY_MSG, fdata->gid[i], fdata->path);
+
+                       internal_log_message(str);
+                       free(str);
+                       continue;
+               }
+
+               status = acl_create_entry_np(&acl, &entry, ACL_FIRST_ENTRY);
+               if (status != 0) goto asl_file_create_return;
+
+               status = acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
+               if (status != 0) goto asl_file_create_return;
+
+               status = acl_set_qualifier(entry, &uuid);
+               if (status != 0) goto asl_file_create_return;
+
+               status = acl_get_permset(entry, &perms);
+               if (status != 0) goto asl_file_create_return;
+
+               status = acl_add_perm(perms, ACL_READ_DATA);
+               if (status != 0) goto asl_file_create_return;
+       }
+
+       for (i = 0; i < fdata->nuid; i++)
+       {
+               status = mbr_uid_to_uuid(fdata->uid[i], uuid);
+               if (status != 0)
+               {
+                       char *str = NULL;
+                       asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [Facility syslog] [%s Unknown UID %d for \"file\" action: %s]",
+                                        ASL_KEY_SENDER,
+                                        ASL_KEY_LEVEL, ASL_LEVEL_ERR,
+                                        ASL_KEY_PID, getpid(),
+                                        ASL_KEY_MSG, fdata->uid[i], fdata->path);
+
+                       internal_log_message(str);
+                       free(str);
+                       continue;
+               }
+
+               status = acl_create_entry_np(&acl, &entry, ACL_FIRST_ENTRY);
+               if (status != 0) goto asl_file_create_return;
+
+               status = acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
+               if (status != 0) goto asl_file_create_return;
+
+               status = acl_set_qualifier(entry, &uuid);
+               if (status != 0) goto asl_file_create_return;
+
+               status = acl_get_permset(entry, &perms);
+               if (status != 0) goto asl_file_create_return;
+
+               status = acl_add_perm(perms, ACL_READ_DATA);
+               if (status != 0) goto asl_file_create_return;
+       }
+
+       mask = umask(0);
+       fd = open(fdata->path, O_RDWR | O_CREAT | O_EXCL, (fdata->mode & 0666));
+       umask(mask);
+       if (fd < 0) goto asl_file_create_return;
+
+       errno = 0;
+       status = acl_set_fd(fd, acl);
+
+       if (status != 0)
+       {
+               close(fd);
+               fd = -1;
+               unlink(fdata->path);
+       }
+
+asl_file_create_return:
+
+       acl_free(acl);
+       return fd;
+#endif
+}
+
+static void
+_act_file_rotate(const char *path)
+{
+       action_rule_t *r;
+       struct file_data *fdata;
+       time_t now = time(NULL);
+
+       for (r = asl_action_rule; r != NULL; r = r->next)
+       {
+               if (r->action == ACTION_FILE)
+               {
+                       fdata = (struct file_data *)r->data;
+                       if (fdata->flags & ACT_FILE_FLAG_ROTATE)
                        {
-                               v64 = global.asl_log_filter;
-                               status = notify_set_state(filter_token, v64);
+                               if ((path == NULL) || ((fdata->path != NULL) && !strcmp(fdata->path, path)))
+                               {
+                                       _act_file_rotate_file_data(fdata, now);
+                               }
                        }
-                       if (status != NOTIFY_STATUS_OK)
+               }
+       }
+}
+
+static char *
+_act_file_format_string(char *s)
+{
+       char *fmt;
+       size_t i, len, n;
+
+       if (s == NULL) return NULL;
+
+       len = strlen(s);
+       n = 0;
+       for (i = 0; i < len; i++) if (s[i] == '\\') n++;
+
+       fmt = malloc(1 + len - n);
+       if (fmt == NULL) return NULL;
+
+       for (i = 0, n = 0; i < len; i++) if (s[i] != '\\') fmt[n++] = s[i];
+       fmt[n] = '\0';
+       return fmt;
+}
+
+static size_t
+_act_file_max_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;
+       else if (x == 'T') n = 1ll << 40;
+
+       max = atoll(s) * n;
+       return max;
+}
+
+static void
+_act_file_add_uid(struct file_data *fdata, char *s)
+{
+       if (fdata == NULL) return;
+       if (s == NULL) return;
+
+       fdata->uid = reallocf(fdata->uid, (fdata->nuid + 1) * sizeof(uid_t));
+       if (fdata->uid == NULL)
+       {
+               fdata->nuid = 0;
+               return;
+       }
+
+       fdata->uid[fdata->nuid++] = atoi(s);
+}
+
+static void
+_act_file_add_gid(struct file_data *fdata, char *s)
+{
+       if (fdata == NULL) return;
+       if (s == NULL) return;
+
+       fdata->gid = reallocf(fdata->gid, (fdata->ngid + 1) * sizeof(gid_t));
+       if (fdata->gid == NULL)
+       {
+               fdata->ngid = 0;
+               return;
+       }
+
+       fdata->gid[fdata->ngid++] = atoi(s);
+}
+
+static void
+_act_file_init(action_rule_t *r)
+{
+       struct file_data *fdata, *xdata;
+       char *str, *opts, *p, *path;
+       action_rule_t *x;
+
+       /* check if the file data is already set up */
+       if (r->data != NULL) return;
+
+       /* requires at least a path */
+       if (r->options == NULL) return;
+       opts = r->options;
+       path = _next_word(&opts);
+
+       if ((path == NULL) || (path[0] != '/'))
+       {
+               str = NULL;
+               asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [Facility syslog] [%s Invalid path for \"file\" action: %s]",
+                                ASL_KEY_SENDER,
+                                ASL_KEY_LEVEL, ASL_LEVEL_ERR,
+                                ASL_KEY_PID, getpid(),
+                                ASL_KEY_MSG, (path == NULL) ? "no path specified" : path);
+
+               internal_log_message(str);
+               free(str);
+               free(path);
+               r->action = ACTION_NONE;
+               return;
+       }
+
+       /* check if a previous rule has set up this path */
+       for (x = asl_action_rule; x != NULL; x = x->next)
+       {
+               if ((x->action == ACTION_FILE) && (x->data != NULL))
+               {
+                       xdata = (struct file_data *)x->data;
+                       if ((xdata->path != NULL) && (!strcmp(path, xdata->path)))
                        {
-                               notify_cancel(filter_token);
-                               filter_token = -1;
+                               free(path);
+                               xdata->refcount++;
+                               r->data = x->data;
+                               return;
                        }
                }
        }
 
-       /* ASLOption "store" forces a message to be saved */
-       log_me = asl_check_option(msg, ASL_OPT_STORE);
-       if (log_me == 1)
+       /* set up file data */
+       fdata = (struct file_data *)calloc(1, sizeof(struct file_data));
+       if (fdata == NULL) return;
+
+       fdata->refcount = 1;
+       fdata->path = path;
+
+       /*
+        * options:
+        * mode=                        set file creation mode
+        * uid=                         user added to read ACL
+        * gid=                         group added to read ACL
+        * format=                      format string (also fmt=)
+        * no_dup_supress       no duplicate supression
+        *
+        * rotate                       automatic daily rotation
+        *                                      this is basic rotation - more support is TBD
+        */
+       fdata->mode = 0644;
+       fdata->flags = ACT_FILE_FLAG_DUP_SUPRESS;
+
+       while (NULL != (p = _next_word(&opts)))
        {
-               db_save_message(msg);
-               return;
+               if (!strncmp(p, "mode=", 5)) fdata->mode = strtol(p+5, NULL, 0);
+               else if (!strncmp(p, "uid=", 4)) _act_file_add_uid(fdata, p+4);
+               else if (!strncmp(p, "gid=", 4)) _act_file_add_gid(fdata, p+4);
+               else if (!strncmp(p, "fmt=", 4)) fdata->fmt = _act_file_format_string(p+4);
+               else if (!strncmp(p, "format=", 7)) fdata->fmt = _act_file_format_string(p+7);
+               else if (!strncmp(p, "no_dup_supress", 14)) fdata->flags &= ~ACT_FILE_FLAG_DUP_SUPRESS;
+               else if (!strncmp(p, "rotate", 6)) fdata->flags |= ACT_FILE_FLAG_ROTATE;
+               else if (!strncmp(p, "max_size=", 9)) fdata->max_size = _act_file_max_size(p+9);
+
+               free(p);
+               p = NULL;
        }
 
-       log_me = 0;
-       if (filter_token >= 0)
+       if (fdata->fmt == NULL) fdata->fmt = strdup("std");
+
+       /* duplicate compression is only possible for std and bsd formats */
+       if (strcmp(fdata->fmt, "std") && strcmp(fdata->fmt, "bsd")) fdata->flags &= ~ACT_FILE_FLAG_DUP_SUPRESS;
+
+       /* set time format for raw output */
+       if (!strcmp(fdata->fmt, "raw")) fdata->tfmt = "sec";
+
+       r->data = fdata;
+}
+
+static void
+_act_file(action_rule_t *r, aslmsg msg)
+{
+       struct file_data *fdata;
+       int is_dup;
+       uint32_t len, msg_hash = 0;
+       char *str;
+       time_t now, today;
+       struct tm ctm;
+
+       if (r->data == NULL) return;
+
+       fdata = (struct file_data *)r->data;
+
+       now = time(NULL);
+       today = now;
+
+       memset(&ctm, 0, sizeof(struct tm));
+       if (localtime_r((const time_t *)&now, &ctm) != NULL)
        {
-               x = 0;
-               status = notify_check(filter_token, &x);
-               if ((status == NOTIFY_STATUS_OK) && (x == 1))
+               ctm.tm_sec = 0;
+               ctm.tm_min = 0;
+               ctm.tm_hour = 0;
+               today = mktime(&ctm);
+       }
+
+       /* check for rotation */
+       if ((last_file_day != 0) && (last_file_day != today))
+       {
+               _act_file_rotate(NULL);
+       }
+
+       last_file_day = today;
+
+
+       /*
+        * asl.conf may contain multuple rules for the same file, eg:
+        *    ? [= Facility zippy] /var/log/abc.log
+        *    ? [= Color purple] /var/log/abc.log
+        *
+        * To prevent duplicates we set a flag bit when a message is logged
+        * to this file, and bail out if it has already been logged.
+        * Note that asl_out_message clears the flag bit in all file_data
+        * structures before processing each message.
+        */
+       if (fdata->flags & ACT_FLAG_HAS_LOGGED) return;
+       fdata->flags |= ACT_FLAG_HAS_LOGGED;
+
+       is_dup = 0;
+
+       str = asl_format_message((asl_msg_t *)msg, fdata->fmt, fdata->tfmt, ASL_ENCODE_SAFE, &len);
+
+       if (fdata->flags & ACT_FILE_FLAG_DUP_SUPRESS)
+       {
+               if (fdata->dup_timer == NULL)
                {
-                       v64 = 0;
-                       status = notify_get_state(filter_token, &v64);
-                       if ((status == NOTIFY_STATUS_OK) && (v64 != 0)) global.asl_log_filter = v64;
+                       /* create a timer to flush dups on this file */
+                       fdata->dup_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, asl_action_queue);
+                       dispatch_source_set_event_handler(fdata->dup_timer, ^{ _act_file_send_repeat_msg((struct file_data *)r->data); });
+               }
+
+               if ((global.bsd_max_dup_time > 0) && (str != NULL) && (fdata->last_msg != NULL))
+               {
+                       msg_hash = asl_core_string_hash(str + 16, len - 16);
+                       if ((fdata->last_hash == msg_hash) && (!strcmp(fdata->last_msg, str + 16)))
+                       {
+                               if ((now - fdata->last_time) < global.bsd_max_dup_time) is_dup = 1;
+                       }
                }
        }
 
-       /* PID 0 (kernel) or PID 1 (launchd) messages are saved */
-       val = asl_get(msg, ASL_KEY_PID);
-       if ((val != NULL) && (atoi(val) <= 1)) log_me = 1;
+       if (is_dup == 1)
+       {
+               if (fdata->last_count == 0)
+               {
+                       /* start the timer */
+                       dispatch_source_set_timer(fdata->dup_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * global.bsd_max_dup_time), DISPATCH_TIME_FOREVER, 0);
+                       dispatch_resume(fdata->dup_timer);
+               }
+
+               fdata->last_count++;
+       }
        else
        {
-               vlevel = asl_get(msg, ASL_KEY_LEVEL);
-               level = 7;
-               if (vlevel != NULL) level = atoi(vlevel);
-               lmask = ASL_FILTER_MASK(level);
-               if ((lmask & global.asl_log_filter) != 0) log_me = 1;
+               fdata->fd = _act_file_open(fdata);
+               if (fdata->fd < 0)
+               {
+                       asldebug("_act_file_open %s failed: %s\n", fdata->path, strerror(errno));
+
+                       fdata->fails++;
+
+                       /* disable further activity after multiple failures */
+                       if (fdata->fails > MAX_FAILURES)
+                       {
+                               char *tmp = NULL;
+                               asprintf(&tmp, "[%s syslogd] [%s %u] [%s %u] [Facility syslog] [%s Disabling writes to path %s following %u failures (%s)]",
+                                                ASL_KEY_SENDER,
+                                                ASL_KEY_LEVEL, ASL_LEVEL_ERR,
+                                                ASL_KEY_PID, getpid(),
+                                                ASL_KEY_MSG, fdata->path, fdata->fails, strerror(errno));
+
+                               internal_log_message(tmp);
+                               free(tmp);
+
+                               r->action = ACTION_NONE;
+                               free(str);
+                               return;
+                       }
+               }
+               else
+               {
+                       fdata->fails = 0;
+               }
+
+               /*
+                * The current message is not a duplicate.  If fdata->last_count > 0
+                * we need to write a "last message repeated N times" log entry.
+                * _act_file_send_repeat_msg will free last_msg and do nothing if
+                * last_count == 0, but we test and free here to avoid a function call.
+                */
+               if (fdata->last_count > 0)
+               {
+                       _act_file_send_repeat_msg(fdata);
+               }
+               else
+               {
+                       free(fdata->last_msg);
+                       fdata->last_msg = NULL;
+               }
+
+               if (str != NULL) fdata->last_msg = strdup(str + 16);
+
+               fdata->last_hash = msg_hash;
+               fdata->last_count = 0;
+               fdata->last_time = now;
+
+               if ((str != NULL) && (len > 1)) write(fdata->fd, str, len - 1);
+               close(fdata->fd);
+               fdata->fd = -1;
        }
 
-       if (log_me == 0) return;
+       free(str);
+}
+
+static void
+_act_forward(action_rule_t *r, aslmsg msg)
+{
+       /* To do: <rdar://problem/6130747> Add a "forward" action to asl.conf */
+}
+
+static void
+_send_to_asl_store(aslmsg msg)
+{
+       int log_me;
+       action_rule_t *r;
+
+       /* ASLOption "store" forces a message to be saved */
+       log_me = asl_check_option(msg, ASL_OPT_STORE);
+       if (log_me == 1)
+       {
+               db_save_message(msg);
+               return;
+       }
 
        /* if there are no rules, save the message */
        if (asl_datastore_rule == NULL)
@@ -1070,39 +1497,62 @@ send_to_asl_store(aslmsg msg)
        }
 }
 
-int
-asl_action_sendmsg(aslmsg msg, const char *outid)
+static void
+_asl_action_message(aslmsg msg)
 {
        action_rule_t *r;
 
-       if (reset != RESET_NONE) _do_reset();
+       if (msg == NULL) return;
 
-       if (msg == NULL) return -1;
+       /* reset flag bit used for file duplicate avoidance */
+       for (r = asl_action_rule; r != NULL; r = r->next)
+       {
+               if ((r->action == ACTION_FILE) && (r->data != NULL))
+               {
+                       ((struct file_data *)(r->data))->flags &= ACT_FLAG_CLEAR_LOGGED;
+               }
+               else if (((r->action == ACTION_ASL_DIR) || (r->action == ACTION_ASL_FILE)) && (r->data != NULL))
+               {
+                       ((struct store_data *)(r->data))->flags &= ACT_FLAG_CLEAR_LOGGED;
+               }
+       }
 
        for (r = asl_action_rule; r != NULL; r = r->next)
        {
                if (asl_msg_cmp(r->query, (asl_msg_t *)msg) == 1)
                {
-                       if ((r->action == ACTION_STORE) || (r->action == ACTION_STORE_DIR))
+                       if ((r->action == ACTION_ASL_FILE) || (r->action == ACTION_ASL_DIR))
                        {
                                _act_store(r, msg);
-                               if (asl_check_option(msg, ASL_OPT_IGNORE) != 0) return -1;
+                               if (asl_check_option(msg, ASL_OPT_IGNORE) != 0) return;
                        }
 
                        if (r->action == ACTION_NONE) continue;
-                       else if (r->action == ACTION_IGNORE) return -1;
+                       else if (r->action == ACTION_IGNORE) return;
                        else if (r->action == ACTION_ACCESS) _act_access_control(r, msg);
                        else if (r->action == ACTION_NOTIFY) _act_notify(r);
                        else if (r->action == ACTION_BROADCAST) _act_broadcast(r, msg);
+                       else if (r->action == ACTION_FILE) _act_file(r, msg);
                        else if (r->action == ACTION_FORWARD) _act_forward(r, msg);
                }
        }
 
-       if (asl_check_option(msg, ASL_OPT_IGNORE) != 0) return -1;
+       if (asl_check_option(msg, ASL_OPT_IGNORE) != 0) return;
 
-       send_to_asl_store(msg);
+       _send_to_asl_store(msg);
+}
 
-       return 0;
+void
+asl_out_message(aslmsg msg)
+{
+       dispatch_flush_continuation_cache();
+
+       asl_msg_retain((asl_msg_t *)msg);
+
+       dispatch_async(asl_action_queue, ^{
+               _asl_action_message(msg);
+               asl_msg_release((asl_msg_t *)msg);
+       });
 }
 
 static int
@@ -1128,42 +1578,68 @@ _parse_config_file(const char *name)
 int
 asl_action_init(void)
 {
-       asldebug("%s: init\n", MY_ID);
-
-       query = asl_msg_new(ASL_TYPE_QUERY);
-       aslevent_addmatch(query, MY_ID);
-       aslevent_addoutput(asl_action_sendmsg, MY_ID);
+       static dispatch_once_t once;
 
+       asldebug("%s: init\n", MY_ID);
        _parse_config_file(_PATH_ASL_CONF);
-       return 0;
-}
 
-int
-asl_action_reset(void)
-{
-       reset = global.reset;
+       dispatch_once(&once, ^{
+               asl_action_queue = dispatch_queue_create("ASL Action Queue", NULL);
+       });
+
        return 0;
 }
 
 int
-asl_action_close(void)
+_asl_action_close_internal(void)
 {
        action_rule_t *r, *n;
        struct store_data *sd;
+       struct file_data *fdata;
        n = NULL;
        for (r = asl_action_rule; r != NULL; r = n)
        {
                n = r->next;
-
-               if (((r->action == ACTION_STORE) || (r->action == ACTION_STORE_DIR) || (r->action == ACTION_NONE)) && (r->data != NULL))
+               if (r->data != NULL)
                {
-                       sd = (struct store_data *)r->data;
-                       if (sd->store != NULL) asl_file_close(sd->store);
-                       if (sd->storedata != NULL) fclose(sd->storedata);
-                       free(sd->path);
-                       free(sd->dir);
-                       sd->store = NULL;
-                       free(sd);
+                       if (((r->action == ACTION_ASL_FILE) || (r->action == ACTION_ASL_DIR) || (r->action == ACTION_NONE)))
+                       {
+                               sd = (struct store_data *)r->data;
+                               if (sd->refcount > 0) sd->refcount--;
+                               if (sd->refcount == 0)
+                               {
+                                       if (sd->store != NULL) asl_file_close(sd->store);
+                                       if (sd->storedata != NULL) fclose(sd->storedata);
+
+                                       free(sd->dir);
+                                       free(sd->path);
+                                       free(sd);
+                               }
+                       }
+
+                       if (r->action == ACTION_FILE)
+                       {
+                               fdata = (struct file_data *)r->data;
+                               if (fdata->refcount > 0) fdata->refcount--;
+                               if (fdata->refcount == 0)
+                               {
+                                       _act_file_send_repeat_msg(fdata);
+
+                                       if (fdata->dup_timer != NULL)
+                                       {
+                                               dispatch_source_cancel(fdata->dup_timer);
+                                               dispatch_resume(fdata->dup_timer);
+                                               dispatch_release(fdata->dup_timer);
+                                       }
+
+                                       free(fdata->path);
+                                       free(fdata->fmt);
+                                       free(fdata->uid);
+                                       free(fdata->gid);
+                                       free(fdata->last_msg);
+                                       free(fdata);
+                               }
+                       }
                }
 
                if (r->query != NULL) asl_msg_release(r->query);
@@ -1189,3 +1665,39 @@ asl_action_close(void)
 
        return 0;
 }
+
+int
+asl_action_close(void)
+{
+       dispatch_async(asl_action_queue, ^{
+               _asl_action_close_internal();
+       });
+
+       return 0;
+}
+
+int
+asl_action_reset(void)
+{
+       dispatch_async(asl_action_queue, ^{
+               _asl_action_close_internal();
+               asl_action_init();
+       });
+
+       return 0;
+}
+
+int
+asl_action_file_rotate(const char *path)
+{
+       /*
+        * The caller may want to know when the rotation has been completed,
+        * so this is synchronous. Also ensures the string stays intact while we work.
+        */
+       dispatch_sync(asl_action_queue, ^{
+               _act_file_rotate(path);
+       });
+
+       return 0;
+}
+
diff --git a/syslogd.tproj/asl_in.c b/syslogd.tproj/asl_in.c
deleted file mode 100644 (file)
index 9229f55..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2004-2010 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 <sys/types.h>
-#include <sys/stat.h>
-#include <sys/fcntl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/uio.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include "daemon.h"
-
-#define forever for(;;)
-
-#define ASL_SOCKET_NAME "AppleSystemLogger"
-#define MY_ID "asl_in"
-
-static int sock = -1;
-
-aslmsg
-asl_in_getmsg(int fd)
-{
-       char *out;
-       aslmsg msg;
-       uint32_t len, n;
-       char tmp[16];
-       int status;
-       uid_t uid;
-       gid_t gid;
-
-       n = read(fd, tmp, 11);
-       if (n < 11)
-       {
-               if (n == 0)
-               {
-                       asl_client_count_decrement();
-
-                       close(fd);
-                       aslevent_removefd(fd);
-                       return NULL;
-               }
-
-               if (n < 0)
-               {
-                       asldebug("%s: read error (len=%d): %s\n", MY_ID, n, strerror(errno));
-                       if (errno != EINTR)
-                       {
-                               asl_client_count_decrement();
-
-                               close(fd);
-                               aslevent_removefd(fd);
-                               return NULL;
-                       }
-               }
-
-               return NULL;
-       }
-
-       len = atoi(tmp);
-       if (len == 0) return NULL;
-
-       out = malloc(len);
-       if (out == NULL) return NULL;
-
-       n = read(fd, out, len);
-       if (n < len)
-       {
-               if (n <= 0)
-               {
-                       asldebug("%s: read error (body): %s\n", MY_ID, strerror(errno));
-                       if (errno != EINTR)
-                       {
-                               asl_client_count_decrement();
-
-                               close(fd);
-                               aslevent_removefd(fd);
-                               free(out);
-                               return NULL;
-                       }
-               }
-       }
-
-       asldebug("asl_in_getmsg: %s\n", (out == NULL) ? "NULL" : out);
-
-       uid = -2;
-       gid = -2;
-
-       status = getpeereid(fd, &uid, &gid);
-       msg = (aslmsg)asl_msg_from_string(out);
-       if (msg == NULL)
-       {
-               free(out);
-               return NULL;
-       }
-
-       snprintf(tmp, sizeof(tmp), "%d", uid);
-       asl_set(msg, ASL_KEY_UID, tmp);
-
-       snprintf(tmp, sizeof(tmp), "%d", gid);
-       asl_set(msg, ASL_KEY_GID, tmp);
-
-       free(out);
-       return msg;
-}
-
-aslmsg
-asl_in_new_connection(int fd)
-{
-       int clientfd;
-
-       asldebug("%s: accepting connection\n", MY_ID);
-       clientfd = accept(fd, NULL, 0);
-       if (clientfd < 0)
-       {
-               asldebug("%s: error connecting socket fd %d: %s\n", MY_ID, fd, strerror(errno));
-               return NULL;
-       }
-
-       if (fcntl(clientfd, F_SETFL, O_NONBLOCK) < 0)
-       {
-               close(clientfd);
-               clientfd = -1;
-               asldebug("%s: couldn't set O_NONBLOCK for fd %d: %s\n", MY_ID, clientfd, strerror(errno));
-               return NULL;
-       }
-
-       asl_client_count_increment();
-
-       aslevent_addfd(SOURCE_ASL_SOCKET, clientfd, ADDFD_FLAGS_LOCAL, asl_in_getmsg, NULL, NULL);
-       return NULL;
-}
-
-int
-asl_in_init(void)
-{
-       int rbufsize;
-       int len;
-       launch_data_t sockets_dict, fd_array, fd_dict;
-
-       asldebug("%s: init\n", MY_ID);
-       if (sock >= 0) return sock;
-       if (global.launch_dict == NULL)
-       {
-               asldebug("%s: launchd dict is NULL\n", MY_ID);
-               return -1;
-       }
-
-       sockets_dict = launch_data_dict_lookup(global.launch_dict, LAUNCH_JOBKEY_SOCKETS);
-       if (sockets_dict == NULL)
-       {
-               asldebug("%s: launchd lookup of LAUNCH_JOBKEY_SOCKETS failed\n", MY_ID);
-               return -1;
-       }
-
-       fd_array = launch_data_dict_lookup(sockets_dict, ASL_SOCKET_NAME);
-       if (fd_array == NULL)
-       {
-               asldebug("%s: launchd lookup of ASL_SOCKET_NAME failed\n", MY_ID);
-               return -1;
-       }
-
-       len = launch_data_array_get_count(fd_array);
-       if (len <= 0)
-       {
-               asldebug("%s: launchd fd array is empty\n", MY_ID);
-               return -1;
-       }
-
-       if (len > 1)
-       {
-               asldebug("%s: warning! launchd fd array has %d sockets\n", MY_ID, len);
-       }
-
-       fd_dict = launch_data_array_get_index(fd_array, 0);
-       if (fd_dict == NULL)
-       {
-               asldebug("%s: launchd file discriptor array element 0 is NULL\n", MY_ID);
-               return -1;
-       }
-
-       sock = launch_data_get_fd(fd_dict);
-
-       rbufsize = 128 * 1024;
-       len = sizeof(rbufsize);
-
-       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rbufsize, len) < 0)
-       {
-               asldebug("%s: couldn't set receive buffer size for %d (%s): %s\n", MY_ID, sock, _PATH_ASL_IN, strerror(errno));
-               close(sock);
-               sock = -1;
-               return -1;
-       }
-
-       if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
-       {
-               asldebug("%s: couldn't set O_NONBLOCK for socket %d (%s): %s\n", MY_ID, sock, _PATH_ASL_IN, strerror(errno));
-               close(sock);
-               sock = -1;
-               return -1;
-       }
-
-       return aslevent_addfd(SOURCE_ASL_SOCKET, sock, ADDFD_FLAGS_LOCAL, asl_in_new_connection, NULL, NULL);
-}
-
-int
-asl_in_close(void)
-{
-       if (sock < 0) return 1;
-
-       aslevent_removefd(sock);
-       close(sock);
-       sock = -1;
-
-       return 0;
-}
-
-int
-asl_in_reset(void)
-{
-       return 0;
-}
index b0df48fd893e9828a9a1982d0427a29658ceee35..afc83d47021e3cc7d4af7822927f8ad9755401a2 100644 (file)
@@ -514,7 +514,6 @@ bb_convert(const char *name)
 
        closedir(dp);
 
-       e = list;
        for (e = list; e != NULL; e = e->next)
        {
                status = do_ASLExpireTime_filter(e->name);
index fa10fd46c68de7a5f7bf3a44a284b02e5fda863a..7595f9c1f33ebbf86a4e9374860b64b5e88f8fa4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #define MAXLINE 4096
 
 static int sock = -1;
+static dispatch_source_t in_src;
+static dispatch_queue_t in_queue;
 
-aslmsg
+void
 bsd_in_acceptmsg(int fd)
 {
        uint32_t len;
        int n;
-       char line[MAXLINE + 1];
+       char line[MAXLINE];
        struct sockaddr_un sun;
+       aslmsg m;
 
        len = sizeof(struct sockaddr_un);
        n = recvfrom(fd, line, MAXLINE, 0, (struct sockaddr *)&sun, &len);
 
-       if (n <= 0) return NULL;
+       if (n <= 0) return;
 
        line[n] = '\0';
 
-       return asl_input_parse(line, n, NULL, SOURCE_BSD_SOCKET);
+       m = asl_input_parse(line, n, NULL, SOURCE_BSD_SOCKET);
+       dispatch_async(global.work_queue, ^{ process_message(m, SOURCE_BSD_SOCKET); });
 }
 
 int
-bsd_in_init(void)
+bsd_in_init()
 {
        int rbufsize;
        int len;
        launch_data_t sockets_dict, fd_array, fd_dict;
+       static dispatch_once_t once;
+       
+       dispatch_once(&once, ^{
+               in_queue = dispatch_queue_create(MY_ID, NULL);
+       });
 
        asldebug("%s: init\n", MY_ID);
-       if (sock >= 0) return sock;
+       if (sock >= 0) return -1;
 
        if (global.launch_dict == NULL)
        {
@@ -128,7 +137,11 @@ bsd_in_init(void)
                return -1;
        }
 
-       return aslevent_addfd(SOURCE_BSD_SOCKET, sock, ADDFD_FLAGS_LOCAL, bsd_in_acceptmsg, NULL, NULL);
+       in_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)sock, 0, in_queue);
+       dispatch_source_set_event_handler(in_src, ^{ bsd_in_acceptmsg(sock); });
+       
+       dispatch_resume(in_src);
+       return 0;
 }
 
 int
@@ -136,7 +149,10 @@ bsd_in_close(void)
 {
        if (sock < 0) return 1;
 
-       aslevent_removefd(sock);
+       dispatch_source_cancel(in_src);
+       dispatch_release(in_src);
+       in_src = NULL;
+
        close(sock);
        sock = -1;
 
index 015283cdc45a125d8b1c3e50cfb4581ea6de54ec..48ab169f0e197acb393f923ddebe60d03ab405ec 100644 (file)
 #define DST_TYPE_WALL 4
 #define DST_TYPE_NOTE 5
 
-#define CLOSE_ON_IDLE_SEC 60
+#define CLOSE_ON_IDLE_SEC 300
 
-static asl_msg_t *query = NULL;
-static int reset = RESET_NONE;
-static pthread_mutex_t reset_lock = PTHREAD_MUTEX_INITIALIZER;
+static dispatch_queue_t bsd_out_queue;
+static dispatch_source_t bsd_idle_timer;
 
 struct config_rule
 {
@@ -71,6 +70,7 @@ struct config_rule
        uint32_t last_hash;
        uint32_t last_count;
        time_t last_time;
+       dispatch_source_t dup_timer;
        char *last_msg;
        TAILQ_ENTRY(config_rule) entries;
 };
@@ -79,35 +79,6 @@ static TAILQ_HEAD(cr, config_rule) bsd_out_rule;
 
 extern uint32_t asl_core_string_hash(const char *s, uint32_t inlen);
 
-int bsd_out_close();
-int bsd_out_network_reset(void);
-static int _parse_config_file(const char *);
-
-static void
-_do_reset(void)
-{
-       pthread_mutex_lock(&reset_lock);
-       if (reset == RESET_NONE)
-       {
-               pthread_mutex_unlock(&reset_lock);
-               return;
-       }
-
-       if (reset == RESET_CONFIG)
-       {
-               bsd_out_close();
-               _parse_config_file(_PATH_SYSLOG_CONF);
-       }
-       else if (reset == RESET_NETWORK)
-       {
-               bsd_out_network_reset();
-       }
-
-       reset = RESET_NONE;
-
-       pthread_mutex_unlock(&reset_lock);
-}
-
 static int
 _level_for_name(const char *name)
 {
@@ -386,7 +357,7 @@ _parse_line(char *s)
 }
 
 static int
-_syslog_send_repeat_msg(struct config_rule *r)
+_bsd_send_repeat_msg(struct config_rule *r)
 {
        char vt[32], *msg;
        time_t tick;
@@ -396,6 +367,9 @@ _syslog_send_repeat_msg(struct config_rule *r)
        if (r->type != DST_TYPE_FILE) return 0;
        if (r->last_count == 0) return 0;
 
+       /* stop the timer */
+       dispatch_suspend(r->dup_timer);
+
        tick = time(NULL);
        memset(vt, 0, sizeof(vt));
        ctime_r(&tick, vt);
@@ -403,6 +377,7 @@ _syslog_send_repeat_msg(struct config_rule *r)
 
        msg = NULL;
        asprintf(&msg, "%s: --- last message repeated %u time%s ---\n", vt + 4, r->last_count, (r->last_count == 1) ? "" : "s");
+       r->last_count = 0;
        if (msg == NULL) return -1;
 
        len = strlen(msg);
@@ -435,7 +410,7 @@ _syslog_send_repeat_msg(struct config_rule *r)
 }
 
 static int
-_syslog_send(aslmsg msg, struct config_rule *r, char **out, char **fwd, time_t now)
+_bsd_send(aslmsg msg, struct config_rule *r, char **out, char **fwd, time_t now)
 {
        char *sf, *outmsg;
        const char *vlevel, *vfacility;
@@ -492,7 +467,6 @@ _syslog_send(aslmsg msg, struct config_rule *r, char **out, char **fwd, time_t n
                *fwd = sf;
        }
 
-       outlen = 0;
        if (r->type == DST_TYPE_SOCK) outlen = strlen(*fwd);
        else outlen = strlen(*out);
 
@@ -502,7 +476,7 @@ _syslog_send(aslmsg msg, struct config_rule *r, char **out, char **fwd, time_t n
                 * If current message is NOT a duplicate and r->last_count > 0
                 * we need to write a "last message was repeated N times" log entry
                 */
-               if ((r->type == DST_TYPE_FILE) && (is_dup == 0) && (r->last_count > 0)) _syslog_send_repeat_msg(r);
+               if ((r->type == DST_TYPE_FILE) && (is_dup == 0) && (r->last_count > 0)) _bsd_send_repeat_msg(r);
 
                do_write = 1;
 
@@ -514,7 +488,24 @@ _syslog_send(aslmsg msg, struct config_rule *r, char **out, char **fwd, time_t n
                 */
                vfacility = asl_get(msg, ASL_KEY_FACILITY);
                if ((vfacility != NULL) && (!strcmp(vfacility, FACILITY_KERNEL)) && (r->type == DST_TYPE_CONS)) do_write = 0;
-               if ((do_write == 1) && (r->type == DST_TYPE_FILE) && (is_dup == 1)) do_write = 0;
+               if ((do_write == 1) && (r->type == DST_TYPE_FILE) && (is_dup == 1))
+               {
+                       do_write = 0;
+
+                       if (r->dup_timer == NULL)
+                       {
+                               /* create a timer to flush dups on this file */
+                               r->dup_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, bsd_out_queue);
+                               dispatch_source_set_event_handler(r->dup_timer, ^{ _bsd_send_repeat_msg(r); });
+                       }
+
+                       if (r->last_count == 0)
+                       {
+                               /* start the timer */
+                               dispatch_source_set_timer(r->dup_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * global.bsd_max_dup_time), DISPATCH_TIME_FOREVER, 0);
+                               dispatch_resume(r->dup_timer);
+                       }
+               }
 
                if (do_write == 0) status = outlen;
                else status = write(r->fd, *out, outlen);
@@ -579,9 +570,10 @@ _syslog_send(aslmsg msg, struct config_rule *r, char **out, char **fwd, time_t n
 }
 
 static int
-_syslog_rule_match(aslmsg msg, struct config_rule *r)
+_bsd_rule_match(aslmsg msg, struct config_rule *r)
 {
-       uint32_t i, test, f, pri;
+       uint32_t i, test, f;
+       int32_t pri;
        const char *val;
 
        if (msg == NULL) return 0;
@@ -634,37 +626,23 @@ _syslog_rule_match(aslmsg msg, struct config_rule *r)
        return test;
 }
 
-int
-bsd_out_sendmsg(aslmsg msg, const char *outid)
+static int
+_bsd_match_and_send(aslmsg msg)
 {
        struct config_rule *r;
        char *out, *fwd;
-       time_t tick;
-       uint64_t delta;
-
-       if (reset != RESET_NONE) _do_reset();
+       time_t now;
 
        if (msg == NULL) return -1;
 
        out = NULL;
        fwd = NULL;
 
-       tick = time(NULL);
-       global.bsd_flush_time = 0;
+       now = time(NULL);
 
        for (r = bsd_out_rule.tqh_first; r != NULL; r = r->entries.tqe_next)
        {
-               if (_syslog_rule_match(msg, r) == 1) _syslog_send(msg, r, &out, &fwd, tick);
-               if ((r->type == DST_TYPE_FILE) && (r->last_count > 0))
-               {
-                       delta = tick - r->last_time;
-                       if (delta < global.bsd_max_dup_time)
-                       {
-                               delta = global.bsd_max_dup_time - delta;
-                               if (global.bsd_flush_time == 0) global.bsd_flush_time = delta;
-                               else if (delta < global.bsd_flush_time) global.bsd_flush_time = delta;
-                       }
-               }
+               if (_bsd_rule_match(msg, r) == 1) _bsd_send(msg, r, &out, &fwd, now);
        }
 
        free(out);
@@ -674,18 +652,34 @@ bsd_out_sendmsg(aslmsg msg, const char *outid)
 }
 
 void
-bsd_close_idle_files(time_t now)
+bsd_out_message(aslmsg msg)
 {
+       if (msg == NULL) return;
+
+       asl_msg_retain((asl_msg_t *)msg);
+
+       dispatch_async(bsd_out_queue, ^{
+               _bsd_match_and_send(msg);
+               asl_msg_release((asl_msg_t *)msg);
+       });
+}
+
+static void
+_bsd_close_idle_files()
+{
+       time_t now;
        struct config_rule *r;
        uint64_t delta;
 
+       now = time(NULL);
+
        for (r = bsd_out_rule.tqh_first; r != NULL; r = r->entries.tqe_next)
        {
                /* only applies to files */
                if (r->type != DST_TYPE_FILE) continue;
 
                /*
-                * If the last message repeat count is non-zero, a bsd_flush_duplicates()
+                * If the last message repeat count is non-zero, a _bsd_flush_duplicates()
                 * call will occur within 30 seconds.  Don't bother closing the file.
                 */
                if (r->last_count > 0) continue;
@@ -695,38 +689,6 @@ bsd_close_idle_files(time_t now)
        }
 }
 
-void
-bsd_flush_duplicates(time_t now)
-{
-       struct config_rule *r;
-       uint64_t delta;
-
-       global.bsd_flush_time = 0;
-
-       for (r = bsd_out_rule.tqh_first; r != NULL; r = r->entries.tqe_next)
-       {
-               if (r->type != DST_TYPE_FILE) continue;
-
-               if (r->last_count > 0)
-               {
-                       delta = now - r->last_time;
-                       if (delta < global.bsd_max_dup_time)
-                       {
-                               delta = global.bsd_max_dup_time - delta;
-                               if (global.bsd_flush_time == 0) global.bsd_flush_time = delta;
-                               else if (delta < global.bsd_flush_time) global.bsd_flush_time = delta;
-                       }
-                       else
-                       {
-                               _syslog_dst_open(r);
-                               _syslog_send_repeat_msg(r);
-
-                               r->last_count = 0;
-                       }
-               }
-       }
-}
-
 static int
 _parse_config_file(const char *confname)
 {
@@ -750,27 +712,28 @@ _parse_config_file(const char *confname)
 int
 bsd_out_init(void)
 {
+       static dispatch_once_t once;
+
        asldebug("%s: init\n", MY_ID);
 
        TAILQ_INIT(&bsd_out_rule);
+       _parse_config_file(_PATH_SYSLOG_CONF);
 
-       query = asl_msg_new(ASL_TYPE_QUERY);
-       aslevent_addmatch(query, MY_ID);
-       aslevent_addoutput(bsd_out_sendmsg, MY_ID);
+       dispatch_once(&once, ^{
+               bsd_out_queue = dispatch_queue_create("BSD Out Queue", NULL);
 
-       _parse_config_file(_PATH_SYSLOG_CONF);
-       return 0;
-}
+               /* start a timer to close idle files */
+               bsd_idle_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, bsd_out_queue);
+               dispatch_source_set_event_handler(bsd_idle_timer, ^{ _bsd_close_idle_files(); });               
+               dispatch_source_set_timer(bsd_idle_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * CLOSE_ON_IDLE_SEC), NSEC_PER_SEC * CLOSE_ON_IDLE_SEC, 0);
+               dispatch_resume(bsd_idle_timer);
+       });
 
-int
-bsd_out_reset(void)
-{
-       reset = global.reset;
        return 0;
 }
 
-int
-bsd_out_close(void)
+static int
+_bsd_out_close_internal(void)
 {
        struct config_rule *r, *n;
        int i;
@@ -780,7 +743,15 @@ bsd_out_close(void)
        {
                n = r->entries.tqe_next;
 
-        free(r->dst);
+               if (r->dup_timer != NULL)
+               {
+                       if (r->last_count > 0) _bsd_send_repeat_msg(r);
+                       dispatch_source_cancel(r->dup_timer);
+                       dispatch_resume(r->dup_timer);
+                       dispatch_release(r->dup_timer);
+               }
+
+               free(r->dst);
                free(r->addr);
                free(r->last_msg);
                free(r->fac_prefix_len);
@@ -796,6 +767,7 @@ bsd_out_close(void)
                        free(r->facility);
                }
 
+               
                TAILQ_REMOVE(&bsd_out_rule, r, entries);
                free(r);
        }
@@ -804,23 +776,22 @@ bsd_out_close(void)
 }
 
 int
-bsd_out_network_reset(void)
+bsd_out_close(void)
 {
-       struct config_rule *r;
+       dispatch_async(bsd_out_queue, ^{
+               _bsd_out_close_internal();
+       });
 
-       for (r = bsd_out_rule.tqh_first; r != NULL; r = r->entries.tqe_next)
-       {
-               if (r->type == DST_TYPE_SOCK) 
-               {
-                       close(r->fd);
-                       r->fd = -1;
-                       if (r->addr != NULL)
-                       {
-                               free(r->addr);
-                               r->addr = NULL;
-                       }
-               }
-       }
+       return 0;
+}
+
+int
+bsd_out_reset(void)
+{
+       dispatch_async(bsd_out_queue, ^{
+               _bsd_out_close_internal();
+               bsd_out_init();
+       });
 
        return 0;
 }
index 6f935b0a72aa912434a4aba9e1a96cd6a9d09c38..5841c5e1e74a5866fea68f9aa76a95c268221970 100644 (file)
        <key>MachServices</key>
        <dict>
                <key>com.apple.system.logger</key>
-               <true/>
+               <dict>
+                       <key>ResetAtClose</key>
+                       <true/>
+               </dict>
        </dict>
        <key>Sockets</key>
        <dict>
index 2d09885280772856f64e3d1263bb4d6236fafc65..ba83182404981fd262995c66580ce14d3fed4f2a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #define VERIFY_STATUS_EXCEEDED_QUOTA 2
 
 extern void disaster_message(aslmsg m);
+extern int asl_action_reset(void);
+
 static char myname[MAXHOSTNAMELEN + 1] = {0};
+static int name_change_token = -1;
 
 static OSSpinLock count_lock = 0;
 
@@ -74,11 +77,23 @@ static vproc_transaction_t vproc_trans = {0};
 #define QUOTA_TABLE_SLOTS 8
 
 #define QUOTA_EXCEEDED_MESSAGE "*** process %d exceeded %d log message per second limit  -  remaining messages this second discarded ***"
+#define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit  -  remaining messages this second discarded ***"
 #define QUOTA_EXCEEDED_LEVEL "3"
 
+#define DEFAULT_DB_FILE_MAX 25600000
+#define DEFAULT_DB_MEMORY_MAX 8192
+#define DEFAULT_DB_MINI_MAX 256
+#define DEFAULT_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
+
 static time_t quota_table_time = 0;
 static pid_t quota_table_pid[QUOTA_TABLE_SIZE];
 static int32_t quota_table_quota[QUOTA_TABLE_SIZE];
+static int32_t kern_quota;
+static int32_t kern_level;
 
 static const char *kern_notify_key[] = 
 {
@@ -92,23 +107,7 @@ static const char *kern_notify_key[] =
        "com.apple.system.log.kernel.debug"
 };
 
-struct asloutput
-{
-       aslsendmsgfn sendmsg;
-       const char *outid;
-       TAILQ_ENTRY(asloutput) entries;
-};
-
-struct aslmatch
-{
-       char *outid;
-       asl_msg_t *query;
-       TAILQ_ENTRY(aslmatch) entries;
-};
-
-TAILQ_HEAD(ae, aslevent) Eventq;
-TAILQ_HEAD(ao, asloutput) Outq;
-TAILQ_HEAD(am, aslmatch) Matchq;
+static int kern_notify_token[8] = {-1, -1, -1, -1, -1, -1, -1, -1 };
 
 static char **
 _insertString(char *s, char **l, uint32_t x)
@@ -231,22 +230,47 @@ freeList(char **l)
  */
  
 static uint32_t
-quota_check(pid_t pid, time_t now, aslmsg msg)
+quota_check(pid_t pid, time_t now, aslmsg msg, uint32_t level)
 {
        int i, x, maxx, max;
-       char *str;
+       char *str, lstr[2];
 
        if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE;
        if (global.mps_limit == 0) return VERIFY_STATUS_OK;
 
-       OSSpinLockLock(&global.lock);
-
        if (quota_table_time != now)
        {
                memset(quota_table_pid, 0, sizeof(quota_table_pid));
+               kern_quota = global.mps_limit;
+               kern_level = 7;
                quota_table_time = now;
        }
 
+       /* kernel gets it's own quota */
+       if (pid == 0)
+       {
+               if (level < kern_level) kern_level = level;
+               if (kern_quota > 0) kern_quota--;
+
+               if (kern_quota > 0) return VERIFY_STATUS_OK;
+               if (kern_quota < 0)     return VERIFY_STATUS_EXCEEDED_QUOTA;
+
+               kern_quota = -1;
+
+               str = NULL;
+               asprintf(&str, QUOTA_KERN_EXCEEDED_MESSAGE, global.mps_limit);
+               if (str != NULL)
+               {
+                       asl_set(msg, ASL_KEY_MSG, str);
+                       free(str);
+                       lstr[0] = kern_level + '0';
+                       lstr[1] = 0;
+                       asl_set(msg, ASL_KEY_LEVEL, lstr);
+               }
+
+               return VERIFY_STATUS_OK;
+       }
+
        /* hash is last 10 bits of the pid, shifted up 3 bits to allow 8 slots per bucket */
        x = (pid & 0x000003ff) << 3;
        maxx = x;
@@ -259,7 +283,6 @@ quota_check(pid_t pid, time_t now, aslmsg msg)
                        quota_table_pid[x] = pid;
                        quota_table_quota[x] = global.mps_limit;
 
-                       OSSpinLockUnlock(&global.lock);
                        return VERIFY_STATUS_OK;
                }
 
@@ -280,17 +303,14 @@ quota_check(pid_t pid, time_t now, aslmsg msg)
                                        asl_set(msg, ASL_KEY_LEVEL, QUOTA_EXCEEDED_LEVEL);
                                }
 
-                               OSSpinLockUnlock(&global.lock);
                                return VERIFY_STATUS_OK;
                        }
 
                        if (quota_table_quota[x] < 0)
                        {
-                               OSSpinLockUnlock(&global.lock);
                                return VERIFY_STATUS_EXCEEDED_QUOTA;
                        }
 
-                       OSSpinLockUnlock(&global.lock);
                        return VERIFY_STATUS_OK;
                }
 
@@ -308,7 +328,6 @@ quota_check(pid_t pid, time_t now, aslmsg msg)
        quota_table_pid[maxx] = pid;
        quota_table_quota[maxx] = global.mps_limit;
 
-       OSSpinLockUnlock(&global.lock);
        return VERIFY_STATUS_OK;
 }
 
@@ -344,153 +363,35 @@ asl_check_option(aslmsg msg, const char *opt)
        return 0;
 }
 
-int
-aslevent_init(void)
-{
-       TAILQ_INIT(&Eventq);
-       TAILQ_INIT(&Outq);
-       TAILQ_INIT(&Matchq);
-
-       return 0;
-}
-
-int
-aslevent_log(aslmsg msg, char *outid)
-{
-       struct asloutput *i;
-       int status = -1;
-
-       for (i = Outq.tqh_first; i != NULL; i = i->entries.tqe_next)
-       {
-               if ((outid != NULL) && (strcmp(i->outid, outid) == 0))
-               {
-                       status = i->sendmsg(msg, outid);
-                       if (status < 0) break;
-               }
-       }
-
-       return status;
-}
-
-int
-aslevent_addmatch(asl_msg_t *query, char *outid)
-{
-       struct aslmatch *tmp;
-
-       if (query == NULL) return -1;
-       if (outid == NULL) return -1;
-
-       tmp = calloc(1, sizeof(struct aslmatch));
-       if (tmp == NULL) return -1;
-
-       tmp->query = query;
-       tmp->outid = outid;
-       TAILQ_INSERT_TAIL(&Matchq, tmp, entries);
-
-       return 0;
-}
-
-void
-asl_message_match_and_log(aslmsg msg)
-{
-       struct aslmatch *i;
-       int status = -1;
-
-       if (msg == NULL) return;
-
-       for (i = Matchq.tqh_first; i != NULL; i = i->entries.tqe_next)
-       {
-               if (asl_msg_cmp(i->query, (asl_msg_t *)msg) != 0)
-               {
-                       status = aslevent_log(msg, i->outid);
-                       if (status < 0) break;
-               }
-       }
-}
-
-int
-aslevent_removefd(int fd)
+const char *
+whatsmyhostname()
 {
-       struct aslevent *e, *next;
-
-       e = Eventq.tqh_first;
-
-       while (e != NULL)
-       {
-               next = e->entries.tqe_next;
-               if (fd == e->fd)
-               {
-                       e->fd = -1;
-                       return 0;
-               }
-
-               e = next;
-       }
-
-       return -1;
-}
+       static dispatch_once_t once;
+       char *dot;
+       int check, status;
 
-static const char *_source_name(int n)
-{
-       switch (n)
-       {
-               case SOURCE_INTERNAL: return "internal";
-               case SOURCE_ASL_SOCKET: return "ASL socket";
-               case SOURCE_BSD_SOCKET: return "BSD socket";
-               case SOURCE_UDP_SOCKET: return "UDP socket";
-               case SOURCE_KERN: return "kernel";
-               case SOURCE_ASL_MESSAGE: return "ASL message";
-               case SOURCE_LAUNCHD: return "launchd";
-               case SOURCE_SESSION: return "session";
-               default: return "unknown";
-       }
+       dispatch_once(&once, ^{
+               snprintf(myname, sizeof(myname), "%s", "localhost");
+               notify_register_check(kNotifySCHostNameChange, &name_change_token);
+       });
 
-       return "unknown";
-}
+       check = 1;
+       status = 0;
 
-void
-aslevent_check()
-{
-       struct aslevent *e, *next;
-       fd_set test;
-       struct timeval zero = {0};
-       int max;
+       if (name_change_token >= 0) status = notify_check(name_change_token, &check);
 
-       e = Eventq.tqh_first;
+       if ((status == 0) && (check == 0)) return (const char *)myname;
 
-       while (e != NULL)
+       if (gethostname(myname, MAXHOSTNAMELEN) < 0)
        {
-               next = e->entries.tqe_next;
-               if (e->fd >= 0)
-               {
-                       FD_ZERO(&test);
-                       FD_SET(e->fd, &test);
-                       max = e->fd + 1;
-
-                       if (select(max, &test, NULL, NULL, &zero) < 0)
-                       {
-                               asldebug("aslevent_check: fd %d source %d (%s) errno %d\n", e->fd, e->source, _source_name(e->source), e->fd);
-                       }
-               }
-
-               e = next;
+               snprintf(myname, sizeof(myname), "%s", "localhost");
        }
-}
-
-const char *
-whatsmyhostname()
-{
-       char *dot;
-
-       if (gethostname(myname, MAXHOSTNAMELEN) < 0)
+       else
        {
-               memset(myname, 0, sizeof(myname));
-               return "localhost";
+               dot = strchr(myname, '.');
+               if (dot != NULL) *dot = '\0';
        }
 
-       dot = strchr(myname, '.');
-       if (dot != NULL) *dot = '\0';
-
        return (const char *)myname;
 }
 
@@ -526,111 +427,6 @@ asl_client_count_decrement()
        OSSpinLockUnlock(&count_lock);
 }
 
-int
-aslevent_addfd(int source, int fd, uint32_t flags, aslreadfn readfn, aslwritefn writefn, aslexceptfn exceptfn)
-{
-       struct aslevent *e;
-       int found = 0, status;
-#ifdef LOCAL_PEERCRED
-       struct xucred cr;
-#endif
-       socklen_t len;
-       uid_t u;
-       gid_t g;
-       struct sockaddr_storage ss;
-       char *sender, str[256];
-
-       u = 99;
-       g = 99;
-       sender = NULL;
-
-       memset(&ss, 0, sizeof(struct sockaddr_storage));
-       memset(str, 0, sizeof(str));
-
-       len = sizeof(struct sockaddr_storage);
-
-       if (flags & ADDFD_FLAGS_LOCAL)
-       {
-               snprintf(str, sizeof(str), "localhost");
-               sender = str;
-
-#ifdef LOCAL_PEERCRED
-               len = sizeof(cr);
-
-               status = getsockopt(fd, LOCAL_PEERCRED, 1, &cr, &len);
-               if (status == 0)
-               {
-                       u = cr.cr_uid;
-                       g = cr.cr_gid;
-               }
-#endif
-       }
-       else
-       {
-               status = getpeername(fd, (struct sockaddr *)&ss, &len);
-               if (status == 0)
-               {
-                       if (len == 0)
-                       {
-                               /* UNIX Domain socket */
-                               snprintf(str, sizeof(str), "localhost");
-                               sender = str;
-                       }
-                       else
-                       {
-                               if (inet_ntop(ss.ss_family, (struct sockaddr *)&ss, str, 256) == NULL) sender = str;
-                       }
-               }
-       }
-
-       asldebug("source %d fd %d   flags 0x%08x UID %d   GID %d   Sender %s\n", source, fd, flags, u, g, (sender == NULL) ? "NULL" : sender );
-
-       for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next)
-       {
-               if (fd == e->fd)
-               {
-                       e->readfn = readfn;
-                       e->writefn = writefn;
-                       e->exceptfn = exceptfn;
-                       if (e->sender != NULL) free(e->sender);
-                       e->sender = NULL;
-                       if (sender != NULL)
-                       {
-                               e->sender = strdup(sender);
-                               if (e->sender == NULL) return -1;
-                       }
-
-                       e->uid = u;
-                       e->gid = g;
-                       found = 1;
-               }
-       }
-
-       if (found) return 0;
-
-       e = calloc(1, sizeof(struct aslevent));
-       if (e == NULL) return -1;
-
-       e->source = source;
-       e->fd = fd;
-       e->readfn = readfn;
-       e->writefn = writefn;
-       e->exceptfn = exceptfn;
-       e->sender = NULL;
-       if (sender != NULL)
-       {
-               e->sender = strdup(sender);
-               if (e->sender == NULL) return -1;
-       }
-
-       e->uid = u;
-       e->gid = g;
-
-       TAILQ_INSERT_TAIL(&Eventq, e, entries);
-
-       return 0;
-}
-
 /*
  * Checks message content and sets attributes as required
  *
@@ -644,40 +440,20 @@ aslevent_addfd(int source, int fd, uint32_t flags, aslreadfn readfn, aslwritefn
  */
 
 static uint32_t
-aslmsg_verify(uint32_t source, struct aslevent *e, aslmsg msg, int32_t *kern_post_level)
+aslmsg_verify(aslmsg msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_out)
 {
        const char *val, *fac, *ruval, *rgval;
        char buf[64];
        time_t tick, now;
        uid_t uid;
+       gid_t gid;
        uint32_t status, level, fnum;
        pid_t pid;
 
        if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE;
 
        if (kern_post_level != NULL) *kern_post_level = -1;
-
-       /* Time */
-       now = time(NULL);
-
-       tick = 0;
-       val = asl_get(msg, ASL_KEY_TIME);
-       if (val != NULL) tick = asl_parse_time(val);
-
-       /* Set time to now if it is unset or from the future (not allowed!) */
-       if ((tick == 0) || (tick > now)) tick = now;
-
-       /* Canonical form: seconds since the epoch */
-       snprintf(buf, sizeof(buf) - 1, "%lu", tick);
-       asl_set(msg, ASL_KEY_TIME, buf);
-
-       /* Host */
-       if (e == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
-       else if (e->sender != NULL)
-       {
-               if (!strcmp(e->sender, "localhost")) asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
-               else asl_set(msg, ASL_KEY_HOST, e->sender);
-       }
+       if (uid_out != NULL) *uid_out = -2;
 
        /* PID */
        pid = 0;
@@ -693,74 +469,63 @@ aslmsg_verify(uint32_t source, struct aslevent *e, aslmsg msg, int32_t *kern_pos
                if (val != NULL) pid = (pid_t)atoi(val);
        }
 
+       /* Time */
+       now = time(NULL);
+
+       /* Level */
+       val = asl_get(msg, ASL_KEY_LEVEL);
+       level = ASL_LEVEL_DEBUG;
+       if ((val != NULL) && (val[1] == '\0') && (val[0] >= '0') && (val[0] <= '7')) level = val[0] - '0';
+       snprintf(buf, sizeof(buf), "%d", level);
+       asl_set(msg, ASL_KEY_LEVEL, buf);
+
        /*
-        * if quotas are enabled and pid > 1 (not kernel or launchd)
-        * and no processes are watching, then check quota
+        * check quota if no processes are watching
         */
-       if ((global.mps_limit > 0) && (pid > 1) && (global.watchers_active == 0))
+       if (global.watchers_active == 0)
        {
-               status = quota_check(pid, now, msg);
+               status = quota_check(pid, now, msg, level);
                if (status != VERIFY_STATUS_OK) return status;
        }
 
-       /* UID */
+       tick = 0;
+       val = asl_get(msg, ASL_KEY_TIME);
+       if (val != NULL) tick = asl_parse_time(val);
+
+       /* Set time to now if it is unset or from the future (not allowed!) */
+       if ((tick == 0) || (tick > now)) tick = now;
+
+       /* Canonical form: seconds since the epoch */
+       snprintf(buf, sizeof(buf) - 1, "%lu", tick);
+       asl_set(msg, ASL_KEY_TIME, buf);
+
+       val = asl_get(msg, ASL_KEY_HOST);
+       if (val == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
+
        uid = -2;
        val = asl_get(msg, ASL_KEY_UID);
-
-       switch (source)
+       if (val != NULL)
        {
-               case SOURCE_KERN:
-               case SOURCE_INTERNAL:
-               {
-                       /* we know the UID is 0 */
-                       uid = 0;
-                       asl_set(msg, ASL_KEY_UID, "0");
-                       break;
-               }
-               case SOURCE_ASL_SOCKET:
-               case SOURCE_ASL_MESSAGE:
-               case SOURCE_LAUNCHD:
-               {
-                       /* we trust the UID in the message */
-                       if (val != NULL) uid = atoi(val);
-                       break;
-               }
-               case SOURCE_BSD_SOCKET:
-               case SOURCE_UDP_SOCKET:
-               {
-                       if (val == NULL)
-                       {
-                               if (e == NULL) asl_set(msg, ASL_KEY_UID, "-2");
-                               else if (e->uid == 99) asl_set(msg, ASL_KEY_UID, "-2");
-                               else
-                               {
-                                       uid = e->uid;
-                                       snprintf(buf, sizeof(buf), "%d", e->uid);
-                                       asl_set(msg, ASL_KEY_UID, buf);
-                               }
-                       }
-                       else if ((e != NULL) && (e->uid != 99))
-                       {
-                               uid = e->uid;
-                               snprintf(buf, sizeof(buf), "%d", e->uid);
-                               asl_set(msg, ASL_KEY_UID, buf);
-                       }
-               }
-               default:
-               {
-                       asl_set(msg, ASL_KEY_UID, "-2");
-               }
+               uid = atoi(val);
+               if ((uid == 0) && strcmp(val, "0")) uid = -2;
+               if (uid_out != NULL) *uid_out = uid;
        }
 
-       /* GID */
+       gid = -2;
        val = asl_get(msg, ASL_KEY_GID);
+       if (val != NULL)
+       {
+               gid = atoi(val);
+               if ((gid == 0) && strcmp(val, "0")) gid = -2;
+       }
 
+       /* UID  & GID */
        switch (source)
        {
                case SOURCE_KERN:
                case SOURCE_INTERNAL:
                {
-                       /* we know the GID is 0 */
+                       asl_set(msg, ASL_KEY_UID, "0");
                        asl_set(msg, ASL_KEY_GID, "0");
                        break;
                }
@@ -768,31 +533,14 @@ aslmsg_verify(uint32_t source, struct aslevent *e, aslmsg msg, int32_t *kern_pos
                case SOURCE_ASL_MESSAGE:
                case SOURCE_LAUNCHD:
                {
-                       /* we trust the GID in the message */
+                       /* we trust the UID & GID in the message */
                        break;
                }
-               case SOURCE_BSD_SOCKET:
-               case SOURCE_UDP_SOCKET:
-               {
-                       if (val == NULL)
-                       {
-                               if (e == NULL) asl_set(msg, ASL_KEY_GID, "-2");
-                               else if (e->gid == 99) asl_set(msg, ASL_KEY_GID, "-2");
-                               else
-                               {
-                                       snprintf(buf, sizeof(buf), "%d", e->gid);
-                                       asl_set(msg, ASL_KEY_GID, buf);
-                               }
-                       }
-                       else if ((e != NULL) && (e->gid != 99))
-                       {
-                               snprintf(buf, sizeof(buf), "%d", e->gid);
-                               asl_set(msg, ASL_KEY_GID, buf);
-                       }
-               }
                default:
                {
-                       asl_set(msg, ASL_KEY_GID, "-2");
+                       /* we do not trust the UID 0 or GID 0 or 80 in the message */
+                       if (uid == 0) asl_set(msg, ASL_KEY_UID, "-2");
+                       if ((gid == 0) || (gid == 80)) asl_set(msg, ASL_KEY_GID, "-2");
                }
        }
 
@@ -824,13 +572,6 @@ aslmsg_verify(uint32_t source, struct aslevent *e, aslmsg msg, int32_t *kern_pos
                asl_set(msg, ASL_KEY_SENDER, "Unknown");
        }
 
-       /* Level */
-       val = asl_get(msg, ASL_KEY_LEVEL);
-       level = ASL_LEVEL_DEBUG;
-       if ((val != NULL) && (val[1] == '\0') && (val[0] >= '0') && (val[0] <= '7')) level = val[0] - '0';
-       snprintf(buf, sizeof(buf), "%d", level);
-       asl_set(msg, ASL_KEY_LEVEL, buf);
-
        /* Facility */
        fac = asl_get(msg, ASL_KEY_FACILITY);
        if (fac == NULL)
@@ -885,10 +626,10 @@ aslmsg_verify(uint32_t source, struct aslevent *e, aslmsg msg, int32_t *kern_pos
                asl_set(msg, ASL_KEY_EXPIRE_TIME, buf);
        }
 
-       /* Set DB Expire Time for Filestsrem errors */
+       /* Set DB Expire Time for Filesystem errors */
        if (!strcmp(fac, FSLOG_VAL_FACILITY))
        {
-               snprintf(buf, sizeof(buf), "%lu", tick + global.fs_ttl);
+               snprintf(buf, sizeof(buf), "%lu", tick + FS_TTL_SEC);
                asl_set(msg, ASL_KEY_EXPIRE_TIME, buf);
        }
 
@@ -904,82 +645,6 @@ aslmsg_verify(uint32_t source, struct aslevent *e, aslmsg msg, int32_t *kern_pos
        return VERIFY_STATUS_OK;
 }
 
-int
-aslevent_addoutput(aslsendmsgfn fn, const char *outid)
-{
-       struct asloutput *tmp;
-
-       tmp = calloc(1, sizeof(struct asloutput));
-       if (tmp == NULL) return -1;
-
-       tmp->sendmsg = fn;
-       tmp->outid = outid;
-
-       TAILQ_INSERT_TAIL(&Outq, tmp, entries);
-
-       return 0;
-}
-
-int
-aslevent_fdsets(fd_set *rd, fd_set *wr, fd_set *ex)
-{
-       struct aslevent *e;
-       int status = 0;
-
-//     asldebug("--> aslevent_fdsets\n");
-       FD_ZERO(rd);
-       FD_ZERO(wr);
-       FD_ZERO(ex);
-
-       for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next)
-       {
-               if (e->fd < 0) continue;
-
-//             asldebug("adding fd %d\n", e->fd);
-               if (e->readfn)
-               {
-                       FD_SET(e->fd, rd);
-                       status = MAX(e->fd, status);
-               }
-
-               if (e->writefn)
-               {
-                       FD_SET(e->fd, wr);
-                       status = MAX(e->fd, status);
-               }
-
-               if (e->exceptfn)
-               {
-                       FD_SET(e->fd, ex);
-                       status = MAX(e->fd, status);
-               }
-       }
-
-//     asldebug("<--aslevent_fdsets\n");
-       return status;
-}
-
-void
-aslevent_cleanup()
-{
-       struct aslevent *e, *next;
-
-       e = Eventq.tqh_first;
-
-       while (e != NULL)
-       {
-               next = e->entries.tqe_next;
-               if (e->fd < 0)
-               {
-                       TAILQ_REMOVE(&Eventq, e, entries);
-                       if (e->sender != NULL) free(e->sender);
-                       free(e);
-               }
-
-               e = next;
-       }
-}
-
 void
 list_append_msg(asl_search_result_t *list, aslmsg msg)
 {
@@ -1016,110 +681,236 @@ list_append_msg(asl_search_result_t *list, aslmsg msg)
 }
 
 void
-work_enqueue(aslmsg m)
+init_globals(void)
 {
-       pthread_mutex_lock(global.work_queue_lock);
-       list_append_msg(global.work_queue, m);
-       pthread_mutex_unlock(global.work_queue_lock);
-       pthread_cond_signal(&global.work_queue_cond);
+       OSSpinLockLock(&global.lock);
+
+       global.debug = 0;
+       free(global.debug_file);
+       global.debug_file = NULL;
+
+#ifdef CONFIG_IPHONE
+       global.dbtype = DB_TYPE_MINI;
+#else
+       global.dbtype = DB_TYPE_FILE;
+#endif
+       global.db_file_max = DEFAULT_DB_FILE_MAX;
+       global.db_memory_max = DEFAULT_DB_MEMORY_MAX;
+       global.db_mini_max = DEFAULT_DB_MINI_MAX;
+       global.mps_limit = DEFAULT_MPS_LIMIT;
+       global.remote_delay_time = DEFAULT_REMOTE_DELAY;
+       global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC;
+       global.mark_time = DEFAULT_MARK_SEC;
+       global.utmp_ttl = DEFAULT_UTMP_TTL_SEC;
+
+       OSSpinLockUnlock(&global.lock);
 }
 
-void
-asl_enqueue_message(uint32_t source, struct aslevent *e, aslmsg msg)
+/*
+ * Used to set config parameters.
+ * Line format "= name value"
+ */
+int
+control_set_param(const char *s)
 {
-       int32_t kplevel;
-       uint32_t status;
+       char **l;
+       uint32_t intval, count, v32a, v32b, v32c;
 
-       if (msg == NULL) return;
+       if (s == NULL) return -1;
+       if (s[0] == '\0') return 0;
 
-       kplevel = -1;
-       status = aslmsg_verify(source, e, msg, &kplevel);
-       if (status == VERIFY_STATUS_OK)
+       /* skip '=' and whitespace */
+       s++;
+       while ((*s == ' ') || (*s == '\t')) s++;
+
+       l = explode(s, " \t");
+       if (l == NULL) return -1;
+
+       for (count = 0; l[count] != NULL; count++);
+
+       /* name is required */
+       if (count == 0)
        {
-               if ((source == SOURCE_KERN) && (kplevel >= 0)) notify_post(kern_notify_key[kplevel]);
-               work_enqueue(msg);
+               freeList(l);
+               return -1;
        }
-       else
+
+       /* value is required */
+       if (count == 1)
        {
-               asl_free(msg);
+               freeList(l);
+               return -1;
        }
-}
-
-aslmsg *
-work_dequeue(uint32_t *count)
-{
-       aslmsg *work;
 
-       pthread_mutex_lock(global.work_queue_lock);
-       if (global.work_queue->count == 0)
+       if (!strcasecmp(l[0], "debug"))
+       {
+               /* = debug {0|1} [file] */
+               intval = atoi(l[1]);
+               config_debug(intval, l[2]);
+       }
+       else if (!strcasecmp(l[0], "mark_time"))
        {
-               pthread_cond_wait(&global.work_queue_cond, global.work_queue_lock);
+               /* = mark_time seconds */
+               OSSpinLockLock(&global.lock);
+               global.mark_time = atoll(l[1]);
+               OSSpinLockUnlock(&global.lock);
        }
+       else if (!strcasecmp(l[0], "dup_delay"))
+       {
+               /* = bsd_max_dup_time seconds */
+               OSSpinLockLock(&global.lock);
+               global.bsd_max_dup_time = atoll(l[1]);
+               OSSpinLockUnlock(&global.lock);
+       }
+       else if (!strcasecmp(l[0], "remote_delay"))
+       {
+               /* = remote_delay microseconds */
+               OSSpinLockLock(&global.lock);
+               global.remote_delay_time = atol(l[1]);
+               OSSpinLockUnlock(&global.lock);
+       }
+       else if (!strcasecmp(l[0], "utmp_ttl"))
+       {
+               /* = utmp_ttl seconds */
+               OSSpinLockLock(&global.lock);
+               global.utmp_ttl = (time_t)atoll(l[1]);
+               OSSpinLockUnlock(&global.lock);
+       }
+       else if (!strcasecmp(l[0], "mps_limit"))
+       {
+               /* = mps_limit number */
+               OSSpinLockLock(&global.lock);
+               global.mps_limit = (uint32_t)atol(l[1]);
+               OSSpinLockUnlock(&global.lock);
+       }
+       else if (!strcasecmp(l[0], "max_file_size"))
+       {
+               /* = max_file_size bytes */
+               pthread_mutex_lock(global.db_lock);
 
-       work = NULL;
-       *count = 0;
+               if (global.dbtype & DB_TYPE_FILE)
+               {
+                       asl_store_close(global.file_db);
+                       global.file_db = NULL;
+                       global.db_file_max = atoi(l[1]);
+               }
 
-       if (global.work_queue->count == 0)
+               pthread_mutex_unlock(global.db_lock);
+       }
+       else if ((!strcasecmp(l[0], "db")) || (!strcasecmp(l[0], "database")) || (!strcasecmp(l[0], "datastore")))
        {
-               pthread_mutex_unlock(global.work_queue_lock);
-               return NULL;
+               /* NB this is private / unpublished */
+               /* = db type [max]... */
+
+               v32a = 0;
+               v32b = 0;
+               v32c = 0;
+
+               if ((l[1][0] >= '0') && (l[1][0] <= '9'))
+               {
+                       intval = atoi(l[1]);
+                       if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
+                       if ((count >= 4) && (strcmp(l[3], "-"))) v32b = atoi(l[3]);
+                       if ((count >= 5) && (strcmp(l[4], "-"))) v32c = atoi(l[4]);
+               }
+               else if (!strcasecmp(l[1], "file"))
+               {
+                       intval = DB_TYPE_FILE;
+                       if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
+               }
+               else if (!strncasecmp(l[1], "mem", 3))
+               {
+                       intval = DB_TYPE_MEMORY;
+                       if ((count >= 3) && (strcmp(l[2], "-"))) v32b = atoi(l[2]);
+               }
+               else if (!strncasecmp(l[1], "min", 3))
+               {
+                       intval = DB_TYPE_MINI;
+                       if ((count >= 3) && (strcmp(l[2], "-"))) v32c = atoi(l[2]);
+               }
+               else
+               {
+                       freeList(l);
+                       return -1;
+               }
+
+               if (v32a == 0) v32a = global.db_file_max;
+               if (v32b == 0) v32b = global.db_memory_max;
+               if (v32c == 0) v32c = global.db_mini_max;
+
+               config_data_store(intval, v32a, v32b, v32c);
        }
 
-       work = (aslmsg *)(global.work_queue->msg);
-       *count = global.work_queue->count;
+       freeList(l);
+       return 0;
+}
 
-       global.work_queue->count = 0;
-       global.work_queue->curr = 0;
-       global.work_queue->msg = NULL;
+static int
+control_message(aslmsg msg)
+{
+       const char *str = asl_get(msg, ASL_KEY_MSG);
 
-       pthread_mutex_unlock(global.work_queue_lock);
-       return work;
+       if (str == NULL) return 0;
+
+       if (!strncmp(str, "= reset", 7))
+       {
+               init_globals();
+               return asl_action_reset();
+       }
+       else if (!strncmp(str, "= rotate", 8))
+       {
+               const char *p = str + 8;
+               while ((*p == ' ') || (*p == '\t')) p++;
+               if (*p == '\0') p = NULL;
+               return asl_action_file_rotate(p);
+       }
+       else if (!strncmp(str, "= ", 2))
+       {
+               return control_set_param(str);
+       }
+
+       return 0;
 }
 
 void
-aslevent_handleevent(fd_set *rd, fd_set *wr, fd_set *ex)
+process_message(aslmsg msg, uint32_t source)
 {
-       struct aslevent *e;
-       char *out = NULL;
-       aslmsg msg;
-       int32_t cleanup;
+       int32_t kplevel;
+       uint32_t status;
+       uid_t uid;
 
-//     asldebug("--> aslevent_handleevent\n");
+       if (msg == NULL) return;
 
-       cleanup = 0;
+       kplevel = -1;
+       uid = -2;
 
-       for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next)
+       status = aslmsg_verify(msg, source, &kplevel, &uid);
+       if (status == VERIFY_STATUS_OK)
        {
-               if (e->fd < 0)
-               {
-                       cleanup = 1;
-                       continue;
-               }
-
-               if (FD_ISSET(e->fd, rd) && (e->readfn != NULL))
+               if ((source == SOURCE_KERN) && (kplevel >= 0))
                {
-//                     asldebug("handling read event on %d\n", e->fd);
-                       msg = e->readfn(e->fd);
-                       if (msg == NULL) continue;
+                       if (kplevel > 7) kplevel = 7;
+                       if (kern_notify_token[kplevel] < 0)
+                       {
+                               status = notify_register_plain(kern_notify_key[kplevel], &(kern_notify_token[kplevel]));
+                               if (status != 0) asldebug("notify_register_plain(%s) failed status %u\n", status);
+                       }
 
-                       asl_enqueue_message(e->source, e, msg);
+                       notify_post(kern_notify_key[kplevel]);
                }
 
-               if (FD_ISSET(e->fd, ex) && e->exceptfn)
-               {
-                       asldebug("handling except event on %d\n", e->fd);
-                       out = e->exceptfn(e->fd);
-                       if (out == NULL) asldebug("error writing message\n\n");
-               }
-       }
+               if ((uid == 0) && asl_check_option(msg, ASL_OPT_CONTROL)) control_message(msg);
 
-       if (cleanup != 0) aslevent_cleanup();
+               /* send message to output modules */
+               asl_out_message(msg);
+               if (global.bsd_out_enabled) bsd_out_message(msg);
+       }
 
-//     asldebug("<-- aslevent_handleevent\n");
+       asl_free(msg);
 }
 
 int
-asl_log_string(const char *str)
+internal_log_message(const char *str)
 {
        aslmsg msg;
 
@@ -1128,7 +919,7 @@ asl_log_string(const char *str)
        msg = (aslmsg)asl_msg_from_string(str);
        if (msg == NULL) return 1;
 
-       asl_enqueue_message(SOURCE_INTERNAL, NULL, msg);
+       dispatch_async(global.work_queue, ^{ process_message(msg, SOURCE_INTERNAL); });
 
        return 0;
 }
@@ -1137,32 +928,21 @@ int
 asldebug(const char *str, ...)
 {
        va_list v;
-       int status;
-       FILE *dfp;
+       FILE *dfp = NULL;
 
-       OSSpinLockLock(&global.lock);
-       if (global.debug == 0)
-       {
-               OSSpinLockUnlock(&global.lock);
-               return 0;
-       }
+       if (global.debug == 0) return 0;
 
-       dfp = stderr;
-       if (global.debug_file != NULL) dfp = fopen(global.debug_file, "a");
-       if (dfp == NULL)
-       {
-               OSSpinLockUnlock(&global.lock);
-               return 0;
-       }
+       if (global.debug_file == NULL) dfp = fopen(_PATH_SYSLOGD_LOG, "a");
+       else dfp = fopen(global.debug_file, "a");
+       if (dfp == NULL) return 0;
 
        va_start(v, str);
-       status = vfprintf(dfp, str, v);
+       vfprintf(dfp, str, v);
        va_end(v);
 
-       if (global.debug_file != NULL) fclose(dfp);
-       OSSpinLockUnlock(&global.lock);
+       fclose(dfp);
 
-       return status;
+       return 0;
 }
 
 void
@@ -1177,7 +957,7 @@ asl_mark(void)
                         ASL_KEY_PID, getpid(),
                         ASL_KEY_MSG, ASL_KEY_UID, ASL_KEY_GID);
 
-       asl_log_string(str);
+       internal_log_message(str);
        if (str != NULL) free(str);
 }
 
@@ -1277,7 +1057,6 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, uint32_t source)
                asl_set(msg, ASL_KEY_MSG, p);
                asl_set(msg, ASL_KEY_LEVEL, prival);
                asl_set(msg, ASL_KEY_PID, "0");
-               asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
 
                return msg;
        }
@@ -1393,11 +1172,15 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, uint32_t source)
        asl_set(msg, ASL_KEY_UID, "-2");
        asl_set(msg, ASL_KEY_GID, "-2");
 
-       if (rhost == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
-       else if (hval != NULL)  asl_set(msg, ASL_KEY_HOST, hval);
-       else asl_set(msg, ASL_KEY_HOST, rhost);
-
-       if (hval != NULL) free(hval);
+       if (hval != NULL)
+       {
+               asl_set(msg, ASL_KEY_HOST, hval);
+               free(hval);
+       }
+       else if (rhost != NULL)
+       {
+               asl_set(msg, ASL_KEY_HOST, rhost);
+       }
 
        return msg;
 }
@@ -1406,7 +1189,7 @@ aslmsg
 asl_input_parse(const char *in, int len, char *rhost, uint32_t source)
 {
        aslmsg msg;
-       int status, x, legacy;
+       int status, x, legacy, off;
 
        asldebug("asl_input_parse: %s\n", (in == NULL) ? "NULL" : in);
 
@@ -1421,7 +1204,8 @@ asl_input_parse(const char *in, int len, char *rhost, uint32_t source)
        /*
         * Determine if the input is "old" syslog format or new ASL format.
         * Old format lines should start with "<", but they can just be straight text.
-        * ASL input starts with a length (10 bytes) followed by a space and a '['.
+        * ASL input may start with a length (10 bytes) followed by a space and a '['.
+        * The length is optional, so ASL messages may also just start with '['.
         */
        if ((in[0] != '<') && (len > 11))
        {
@@ -1431,7 +1215,10 @@ asl_input_parse(const char *in, int len, char *rhost, uint32_t source)
 
        if (legacy == 1) return asl_syslog_input_convert(in, len, rhost, source);
 
-       msg = (aslmsg)asl_msg_from_string(in + 11);
+       off = 11;
+       if (in[0] == '[') off = 0;
+
+       msg = (aslmsg)asl_msg_from_string(in + off);
        if (msg == NULL) return NULL;
 
        if (rhost != NULL) asl_set(msg, ASL_KEY_HOST, rhost);
@@ -1454,6 +1241,7 @@ get_line_from_file(FILE *f)
 
        memcpy(s, out, len);
 
+       if (s[len - 1] != '\n') len++;
        s[len - 1] = '\0';
        return s;
 }
@@ -1496,9 +1284,6 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se
                asl_set(m, ASL_KEY_TIME, str);
        }
 
-       /* Host */
-       asl_set(m, ASL_KEY_HOST, whatsmyhostname());
-
        /* Facility */
        asl_set(m, ASL_KEY_FACILITY, FACILITY_CONSOLE);
 
@@ -1558,15 +1343,6 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se
                asl_set(m, ASL_KEY_MSG, msg);
        }
 
-       /* verify and push to receivers */
-       asl_enqueue_message(SOURCE_LAUNCHD, NULL, m);
+       dispatch_async(global.work_queue, ^{ process_message(m, SOURCE_LAUNCHD); });
 }
 
-void
-launchd_drain()
-{
-       forever
-       {
-               _vprocmgr_log_drain(NULL, NULL, launchd_callback);
-       }
-}
index 1c41ec8f5faf4d01c49b21d7c5af0f4c0d857996..4e7ca1574d29f74402455c3aede11d787527897b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <time.h>
 #include <asl.h>
 #include <asl_msg.h>
+#include <asl_core.h>
 #include <asl_private.h>
 #include <asl_store.h>
 #include "asl_memory.h"
 #include "asl_mini_memory.h"
 #include <notify.h>
+#include <notify_keys.h>
 #include <launch.h>
+#include <dispatch/dispatch.h>
 #include <libkern/OSAtomic.h>
 
 #define ADDFD_FLAGS_LOCAL 0x00000001
 
-#define ASL_DB_NOTIFICATION "com.apple.system.logger.message"
 #define SELF_DB_NOTIFICATION "self.logger.message"
 
 #define ASL_OPT_IGNORE "ignore"
 #define ASL_OPT_STORE "store"
+#define ASL_OPT_CONTROL "control"
+#define ASL_OPT_DB_FILE "asl_db_file"
+#define ASL_OPT_DB_MINI "asl_db_mini_memory"
+#define ASL_OPT_DB_MEMORY "asl_db_memory"
 
 #define _PATH_PIDFILE          "/var/run/syslog.pid"
-#define _PATH_ASL_IN           "/var/run/asl_input"
 #define _PATH_SYSLOG_CONF   "/etc/syslog.conf"
 #define _PATH_SYSLOG_IN                "/var/run/syslog"
 #define _PATH_KLOG                     "/dev/klog"
-#define _PATH_MODULE_LIB       "/usr/lib/asl"
+#define _PATH_SYSLOGD_LOG      "/var/log/syslogd.log"
 
 #define DB_TYPE_FILE   0x00000001
 #define DB_TYPE_MEMORY 0x00000002
 
 #define STORE_FLAGS_FILE_CACHE_SWEEP_REQUESTED 0x00000001
 
-#define RESET_NONE 0
-#define RESET_CONFIG 1
-#define RESET_NETWORK 2
+#define FS_TTL_SEC 31622400
+
+typedef struct
+{
+       const char *name;
+       int enabled;
+       int (*init)(void);
+       int (*reset)(void);
+       int (*close)(void);
+} module_t;
 
 struct global_s
 {
@@ -83,27 +95,28 @@ struct global_s
        int disaster_occurred;
        mach_port_t listen_set;
        mach_port_t server_port;
-       mach_port_t self_port;
        mach_port_t dead_session_port;
        launch_data_t launch_dict;
        uint32_t store_flags;
        time_t start_time;
        int lockdown_session_fd;
        int watchers_active;
-       int kfd;
        int reset;
        uint64_t bsd_flush_time;
        pthread_mutex_t *db_lock;
-       pthread_mutex_t *work_queue_lock;
        pthread_cond_t work_queue_cond;
-       asl_search_result_t *work_queue;
+       dispatch_queue_t work_queue;
+       dispatch_source_t mark_timer;
+       dispatch_source_t sig_hup_src;
        asl_store_t *file_db;
        asl_memory_t *memory_db;
        asl_mini_memory_t *mini_db;
        asl_mini_memory_t *disaster_db;
+       int module_count;
+       int bsd_out_enabled;
+       module_t **module;
 
        /* parameters below are configurable as command-line args or in /etc/asl.conf */
-       int asl_log_filter;
        int debug;
        char *debug_file;
        int dbtype;
@@ -111,59 +124,24 @@ struct global_s
        uint32_t db_memory_max;
        uint32_t db_mini_max;
        uint32_t mps_limit;
+       uint32_t remote_delay_time;
        uint64_t bsd_max_dup_time;
-       uint64_t asl_store_ping_time;
        uint64_t mark_time;
        time_t utmp_ttl;
-       time_t fs_ttl;
 };
 
 extern struct global_s global;
 
-typedef aslmsg (*aslreadfn)(int);
-typedef char *(*aslwritefn)(const char *, int);
-typedef char *(*aslexceptfn)(int);
-typedef int (*aslsendmsgfn)(aslmsg msg, const char *outid);
-
-struct aslevent
-{
-       int source;
-       int fd;
-       unsigned char read:1; 
-       unsigned char write:1; 
-       unsigned char except:1;
-       aslreadfn readfn;
-       aslwritefn writefn;
-       aslexceptfn exceptfn;
-       char *sender;
-       uid_t uid;
-       gid_t gid;
-       TAILQ_ENTRY(aslevent) entries;
-};
-
-struct module_list
-{
-       char *name;
-       void *module;
-       int (*init)(void);
-       int (*reset)(void);
-       int (*close)(void);
-       TAILQ_ENTRY(module_list) entries;
-};
+void init_globals(void);
 
 void config_debug(int enable, const char *path);
 void config_data_store(int type, uint32_t file_max, uint32_t memory_max, uint32_t mini_max);
-void config_timers(uint64_t bsd_max_dup, uint64_t asl_store_ping, uint64_t utmp, uint64_t fs);
 
 char **explode(const char *s, const char *delim);
 void freeList(char **l);
 
-int aslevent_init(void);
-int aslevent_fdsets(fd_set *, fd_set *, fd_set *);
-void aslevent_handleevent(fd_set *, fd_set *, fd_set *);
 void asl_mark(void);
 void asl_archive(void);
-void aslevent_check(void);
 
 void asl_client_count_increment();
 void asl_client_count_decrement();
@@ -171,30 +149,28 @@ void asl_client_count_decrement();
 char *get_line_from_file(FILE *f);
 
 int asldebug(const char *, ...);
-int asl_log_string(const char *str);
+int internal_log_message(const char *str);
 
 asl_msg_t *asl_msg_from_string(const char *buf);
 int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
 time_t asl_parse_time(const char *str);
 
-int aslevent_addfd(int source, int fd, uint32_t flags, aslreadfn readfn, aslwritefn writefn, aslexceptfn exceptfn);
-int aslevent_removefd(int fd);
-int aslevent_addmatch(asl_msg_t *query, char *outid);
-
 int asl_check_option(aslmsg msg, const char *opt);
 
-int aslevent_addoutput(aslsendmsgfn, const char *outid);
-
-void asl_enqueue_message(uint32_t source, struct aslevent *e, aslmsg msg);
-aslmsg *work_dequeue(uint32_t *count);
-void asl_message_match_and_log(aslmsg msg);
 void send_to_direct_watchers(asl_msg_t *msg);
 
+void launchd_callback();
+
 int asl_syslog_faciliy_name_to_num(const char *fac);
 const char *asl_syslog_faciliy_num_to_name(int num);
 aslmsg asl_input_parse(const char *in, int len, char *rhost, uint32_t source);
 
-void db_ping_store(void);
+const char *whatsmyhostname();
+void process_message(aslmsg m, uint32_t source);
+void asl_out_message(aslmsg msg);
+int asl_action_file_rotate(const char *path);
+void bsd_out_message(aslmsg msg);
+int control_set_param(const char *s);
 
 /* notify SPI */
 uint32_t notify_register_plain(const char *name, int *out_token);
index c8d37ac76aea2087c93d87d886c1762376542786..ecdec48e6d74f641758308e54cdc52988eff09df 100644 (file)
 #include <pthread.h>
 #include <notify.h>
 #include <sys/time.h>
-#include <asl.h>
+#include "daemon.h"
 #include "asl_ipc.h"
 #include "asl_ipcServer.h"
-#include <asl_core.h>
-#include <asl_store.h>
-#include "daemon.h"
 
 #define forever for(;;)
 
@@ -61,7 +58,9 @@
 #define SEARCH_FORWARD 1
 #define SEARCH_BACKWARD -1
 
-static pthread_mutex_t db_lock = PTHREAD_MUTEX_INITIALIZER;
+#define MAX_AGAIN 100
+
+static dispatch_queue_t asl_server_queue;
 
 extern char *asl_list_to_string(asl_search_result_t *list, uint32_t *outlen);
 extern asl_search_result_t *asl_list_from_string(const char *buf);
@@ -88,25 +87,13 @@ typedef union
        union __ReplyUnion__asl_ipc_subsystem reply;
 } asl_reply_msg;
 
-void
-db_ping_store(void)
-{
-       if ((global.dbtype & DB_TYPE_FILE) && (global.file_db != NULL))
-       {
-               global.store_flags |= STORE_FLAGS_FILE_CACHE_SWEEP_REQUESTED;
-
-               /* wake up the output worker thread */
-               pthread_cond_signal(&global.work_queue_cond);
-       }
-}
-
-void
-db_asl_open()
+static void
+db_asl_open(uint32_t dbtype)
 {
        uint32_t status;
        struct stat sb;
 
-       if ((global.dbtype & DB_TYPE_FILE) && (global.file_db == NULL))
+       if ((dbtype & DB_TYPE_FILE) && (global.file_db == NULL))
        {
                memset(&sb, 0, sizeof(struct stat));
                if (stat(PATH_ASL_STORE, &sb) == 0)
@@ -159,7 +146,7 @@ db_asl_open()
                }
        }
 
-       if ((global.dbtype & DB_TYPE_MEMORY) && (global.memory_db == NULL))
+       if ((dbtype & DB_TYPE_MEMORY) && (global.memory_db == NULL))
        {
                status = asl_memory_open(global.db_memory_max, &(global.memory_db));
                if (status != ASL_STATUS_OK)
@@ -168,7 +155,7 @@ db_asl_open()
                }
        }
 
-       if ((global.dbtype & DB_TYPE_MINI) && (global.mini_db == NULL))
+       if ((dbtype & DB_TYPE_MINI) && (global.mini_db == NULL))
        {
                status = asl_mini_memory_open(global.db_mini_max, &(global.mini_db));
                if (status != ASL_STATUS_OK)
@@ -178,89 +165,77 @@ db_asl_open()
        }
 }
 
-/*
- * Takes messages off the work queue and saves them.
- * Runs in it's own thread.
- */
 void
-output_worker()
+send_to_direct_watchers(asl_msg_t *msg)
 {
-       aslmsg *work;
-       uint32_t i, count;
-       mach_msg_empty_send_t *empty;
-       kern_return_t kstatus;
+       uint32_t i, j, nlen, outlen, cleanup, total_sent, again;
+       ssize_t sent;
+       char *out;
 
-       empty = (mach_msg_empty_send_t *)calloc(1, sizeof(mach_msg_empty_send_t));
-       if (empty == NULL) return;
+#ifdef LOCKDOWN
+       static struct timeval last_time;
 
-       forever
+       if (global.lockdown_session_fd >= 0)
        {
-               count = 0;
-
-               /* blocks until work is available */
-               work = work_dequeue(&count);
-
-               if (work == NULL)
+               if (global.remote_delay_time > 0)
                {
-                       if ((global.dbtype & DB_TYPE_FILE) && (global.store_flags & STORE_FLAGS_FILE_CACHE_SWEEP_REQUESTED))
+                       struct timeval now;
+                       uint64_t delta;
+                       
+                       if (gettimeofday(&now, NULL) == 0)
                        {
-                               asl_store_sweep_file_cache(global.file_db);
-                               global.store_flags &= ~STORE_FLAGS_FILE_CACHE_SWEEP_REQUESTED;
-                       }
-
-                       continue;
-               }
-
-               for (i = 0; i < count; i++)
-               {
-                       asl_message_match_and_log(work[i]);
-                       asl_free(work[i]);
-               }
+                               if (last_time.tv_sec != 0)
+                               {
+                                       if (now.tv_sec > last_time.tv_sec)
+                                       {
+                                               now.tv_sec -= 1;
+                                               now.tv_usec += 1000000;
+                                       }
+                                       
+                                       delta = now.tv_sec - last_time.tv_sec;
+                                       delta *= 1000000;
+                                       delta += (now.tv_usec - last_time.tv_usec);
+                                       if (delta < global.remote_delay_time)
+                                       {
+                                               usleep(delta);
+                                       }
+                               }
 
-               free(work);
+                               if (now.tv_usec >= 1000000)
+                               {
+                                       now.tv_sec += 1;
+                                       now.tv_usec -= 1000000;
+                               }
 
-               if (global.store_flags & STORE_FLAGS_FILE_CACHE_SWEEP_REQUESTED)
-               {
-                       asl_store_sweep_file_cache(global.file_db);
-                       global.store_flags &= ~STORE_FLAGS_FILE_CACHE_SWEEP_REQUESTED;
+                               last_time = now;
+                       }
                }
 
-               empty->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO);
-               empty->header.msgh_remote_port = global.self_port;
-               empty->header.msgh_local_port = MACH_PORT_NULL;
-               empty->header.msgh_size = sizeof(mach_msg_empty_send_t);
-               empty->header.msgh_id = SEND_NOTIFICATION;
-
-               kstatus = mach_msg(&(empty->header), MACH_SEND_MSG | MACH_SEND_TIMEOUT, empty->header.msgh_size, 0, MACH_PORT_NULL, 100, MACH_PORT_NULL);
-       }
-}
-
-void
-send_to_direct_watchers(asl_msg_t *msg)
-{
-       uint32_t i, j, nlen, outlen, cleanup, total_sent;
-       ssize_t sent;
-       char *out;
-
-#ifdef LOCKDOWN
-       if (global.lockdown_session_fd >= 0)
-       {
-               /* PurpleConsole eats newlines */
                out = asl_format_message(msg, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &outlen);
-               if ((write(global.lockdown_session_fd, "\n", 1) < 0) || 
-                       (write(global.lockdown_session_fd, out, outlen) < 0) ||
-                       (write(global.lockdown_session_fd, "\n", 1) < 0))
+               if ((write(global.lockdown_session_fd, out, outlen) < 0) || (write(global.lockdown_session_fd, "\n", 1) < 0))
                {
+                       asldebug("send_to_direct_watchers: lockdown write error: %d %s\n", errno, strerror(errno));
                        close(global.lockdown_session_fd);
                        global.lockdown_session_fd = -1;
                        global.watchers_active = direct_watch_count + ((global.lockdown_session_fd < 0) ? 0 : 1);
                }
 
                free(out);
+
        }
 #endif
 
-       if (direct_watch_count == 0) return;
+       if (direct_watch_count == 0)
+       {
+               direct_watch = NULL;
+               return;
+       }
+
+       if (direct_watch == NULL)
+       {
+               direct_watch_count = 0;
+               return;
+       }
 
        cleanup = 0;
        out = asl_msg_to_string(msg, &outlen);
@@ -281,11 +256,30 @@ send_to_direct_watchers(asl_msg_t *msg)
                else
                {
                        total_sent = 0;
+                       again = 0;
+
                        while (total_sent < outlen)
                        {
+                               errno = 0;
                                sent = send(direct_watch[i], out + total_sent, outlen - total_sent, 0);
-                               if (sent < 0)
+                               if (sent <= 0)
                                {
+                                       asldebug("send_to_direct_watchers: send returned %d (errno %d)\n", sent, errno);
+                                       if (errno == EAGAIN)
+                                       {
+                                               if (again > MAX_AGAIN)
+                                               {
+                                                       asldebug("send_to_direct_watchers: exceeded EAGAIN limit - closing connection\n");
+                                                       break;
+                                               }
+                                               else
+                                               {
+                                                       again++;
+                                                       errno = 0;
+                                                       continue;
+                                               }
+                                       }
+
                                        close(direct_watch[i]);
                                        direct_watch[i] = -1;
                                        cleanup = 1;
@@ -348,15 +342,32 @@ void
 db_save_message(aslmsg msg)
 {
        uint64_t msgid;
-       uint32_t status;
+       uint32_t status, dbtype;
+       static int armed;
+       static dispatch_source_t timer_src;
+       static dispatch_once_t once;
+
+       dispatch_once(&once, ^{
+               timer_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
+               dispatch_source_set_event_handler(timer_src, ^{
+                       notify_post(kNotifyASLDBUpdate);
+                       dispatch_suspend(timer_src);
+                       armed = 0;
+               });
+               armed = 0;
+       });
 
        send_to_direct_watchers((asl_msg_t *)msg);
 
-       pthread_mutex_lock(&db_lock);
+       dbtype = global.dbtype;
+
+       if (asl_check_option(msg, ASL_OPT_DB_FILE))   dbtype |= DB_TYPE_FILE;
+       if (asl_check_option(msg, ASL_OPT_DB_MINI))   dbtype |= DB_TYPE_MINI;
+       if (asl_check_option(msg, ASL_OPT_DB_MEMORY)) dbtype |= DB_TYPE_MEMORY;
 
-       db_asl_open();
+       db_asl_open(dbtype);
 
-       if (global.dbtype & DB_TYPE_FILE)
+       if (dbtype & DB_TYPE_FILE)
        {
                status = asl_store_save(global.file_db, msg);
                if (status != ASL_STATUS_OK)
@@ -366,7 +377,7 @@ db_save_message(aslmsg msg)
                        asl_store_close(global.file_db);
                        global.file_db = NULL;
 
-                       db_asl_open();
+                       db_asl_open(dbtype);
                        status = asl_store_save(global.file_db, msg);
                        if (status != ASL_STATUS_OK)
                        {
@@ -375,6 +386,7 @@ db_save_message(aslmsg msg)
                                global.file_db = NULL;
 
                                global.dbtype |= DB_TYPE_MEMORY;
+                               dbtype |= DB_TYPE_MEMORY;
                                if (global.memory_db == NULL)
                                {
                                        status = asl_memory_open(global.db_memory_max, &(global.memory_db));
@@ -387,7 +399,7 @@ db_save_message(aslmsg msg)
                }
        }
 
-       if (global.dbtype & DB_TYPE_MEMORY)
+       if (dbtype & DB_TYPE_MEMORY)
        {
                msgid = 0;
                status = asl_memory_save(global.memory_db, msg, &msgid);
@@ -398,7 +410,7 @@ db_save_message(aslmsg msg)
                        asl_memory_close(global.memory_db);
                        global.memory_db = NULL;
 
-                       db_asl_open();
+                       db_asl_open(dbtype);
                        msgid = 0;
                        status = asl_memory_save(global.memory_db, msg, &msgid);
                        if (status != ASL_STATUS_OK)
@@ -410,7 +422,7 @@ db_save_message(aslmsg msg)
                }
        }
 
-       if (global.dbtype & DB_TYPE_MINI)
+       if (dbtype & DB_TYPE_MINI)
        {
                status = asl_mini_memory_save(global.mini_db, msg, &msgid);
                if (status != ASL_STATUS_OK)
@@ -420,7 +432,7 @@ db_save_message(aslmsg msg)
                        asl_mini_memory_close(global.mini_db);
                        global.mini_db = NULL;
 
-                       db_asl_open();
+                       db_asl_open(dbtype);
                        status = asl_mini_memory_save(global.mini_db, msg, &msgid);
                        if (status != ASL_STATUS_OK)
                        {
@@ -431,7 +443,12 @@ db_save_message(aslmsg msg)
                }
        }
 
-       pthread_mutex_unlock(&db_lock);
+       if (armed == 0)
+       {
+               armed = 1;
+               dispatch_source_set_timer(timer_src, dispatch_walltime(NULL, NSEC_PER_SEC / 2), DISPATCH_TIME_FOREVER, 0);
+               dispatch_resume(timer_src);
+       }
 }
 
 void
@@ -476,8 +493,6 @@ db_query(aslresponse query, aslresponse *res, uint64_t startid, int count, int f
        dir = SEARCH_FORWARD;
        if (flags & QUERY_FLAG_SEARCH_REVERSE) dir = SEARCH_BACKWARD;
 
-       pthread_mutex_lock(&db_lock);
-
        status = ASL_STATUS_FAILED;
 
        if (global.dbtype & DB_TYPE_MEMORY)
@@ -494,8 +509,6 @@ db_query(aslresponse query, aslresponse *res, uint64_t startid, int count, int f
                status = asl_mini_memory_match(global.mini_db, query, res, lastid, startid, ucount, dir);
        }
 
-       pthread_mutex_unlock(&db_lock);
-
        return status;
 }
 
@@ -572,6 +585,7 @@ cancel_session(task_name_t task_name)
 static uint32_t
 register_direct_watch(uint16_t port)
 {
+#ifdef CONFIG_IPHONE
        uint32_t i;
        int sock, flags;
        struct sockaddr_in address;
@@ -633,11 +647,15 @@ register_direct_watch(uint16_t port)
        global.watchers_active = direct_watch_count + ((global.lockdown_session_fd < 0) ? 0 : 1);
 
        return ASL_STATUS_OK;
+#else
+       return ASL_STATUS_FAILED;
+#endif
 }
 
 static void
 cancel_direct_watch(uint16_t port)
 {
+#ifdef CONFIG_IPHONE
        uint32_t i;
 
        for (i = 0; (i < direct_watch_count) && (port != direct_watch_port[i]); i++);
@@ -683,6 +701,7 @@ cancel_direct_watch(uint16_t port)
                        if (global.lockdown_session_fd >= 0) global.watchers_active = 1;
                }
        }
+#endif
 }
 
 /*
@@ -693,12 +712,10 @@ cancel_direct_watch(uint16_t port)
 void
 database_server()
 {
-       kern_return_t kstatus;
        asl_request_msg *request;
-       asl_reply_msg *reply;
-       uint32_t rqs, rps;
+       uint32_t rqs;
        uint32_t rbits, sbits;
-       uint32_t flags, snooze;
+       uint32_t flags;
        struct timeval now, send_time;
        mach_dead_name_notification_t *deadname;
 
@@ -706,81 +723,55 @@ database_server()
        send_time.tv_usec = 0;
 
        rqs = sizeof(asl_request_msg) + MAX_TRAILER_SIZE;
-       rps = sizeof(asl_reply_msg) + MAX_TRAILER_SIZE;
-       reply = (asl_reply_msg *)calloc(1, rps);
-       if (reply == NULL) return;
 
        rbits = MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0);
        sbits = MACH_SEND_MSG | MACH_SEND_TIMEOUT;
 
+       asl_server_queue = dispatch_queue_create("ASL Server Queue", NULL);
+
        forever
        {
-               snooze = 0;
                now.tv_sec = 0;
                now.tv_usec = 0;
 
-               /* Check if it's time to post a database change notification */
-               if (send_time.tv_sec != 0)
-               {
-                       gettimeofday(&now, NULL);
-                       if ((now.tv_sec > send_time.tv_sec) || ((now.tv_sec == send_time.tv_sec) && (now.tv_usec > send_time.tv_usec)))
-                       {
-                               notify_post(ASL_DB_NOTIFICATION);
-                               send_time.tv_sec = 0;
-                               send_time.tv_usec = 0;
-                               snooze = 0;
-                       }
-                       else
-                       {
-                               /* mach_msg timeout is in milliseconds */
-                               snooze = ((send_time.tv_sec - now.tv_sec) * 1000) + ((send_time.tv_usec - now.tv_usec) / 1000);
-                       }
-               }
-
                request = (asl_request_msg *)calloc(1, rqs);
                if (request == NULL) continue;
 
                request->head.msgh_local_port = global.server_port;
                request->head.msgh_size = rqs;
 
-               memset(reply, 0, rps);
-
                flags = rbits;
-               if (snooze != 0) flags |= MACH_RCV_TIMEOUT;
 
-               kstatus = mach_msg(&(request->head), flags, 0, rqs, global.listen_set, snooze, MACH_PORT_NULL);
-               if (request->head.msgh_id == SEND_NOTIFICATION)
-               {
-                       if (send_time.tv_sec == 0)
-                       {
-                               gettimeofday(&send_time, NULL);
-                               send_time.tv_sec += 1;
-                       }
-
-                       free(request);
-                       continue;
-               }
+               (void)mach_msg(&(request->head), flags, 0, rqs, global.listen_set, 0, MACH_PORT_NULL);
 
                if (request->head.msgh_id == MACH_NOTIFY_DEAD_NAME)
                {
                        deadname = (mach_dead_name_notification_t *)request;
-                       cancel_session(deadname->not_port);
+                       dispatch_async(asl_server_queue, ^{
+                               cancel_session(deadname->not_port);
+                               /* dead name notification includes a dead name right */
+                               mach_port_deallocate(mach_task_self(), deadname->not_port);
+                               free(request);
+                       });
 
-                       /* dead name notification includes a dead name right - release it here */
-                       mach_port_deallocate(mach_task_self(), deadname->not_port);
-                       free(request);
                        continue;
                }
 
-               kstatus = asl_ipc_server(&(request->head), &(reply->head));
-               kstatus = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL);
-               if (kstatus == MACH_SEND_INVALID_DEST)
-               {
-                       /* release send right for the port */
-                       mach_port_deallocate(mach_task_self(), request->head.msgh_remote_port);
-               }
+               dispatch_async(asl_server_queue, ^{
+                       kern_return_t ks;
+                       asl_reply_msg *reply = calloc(1, sizeof(asl_reply_msg) + MAX_TRAILER_SIZE);
+                       
+                       asl_ipc_server(&(request->head), &(reply->head));
+                       ks = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL);
+                       free(reply);
+                       if ((ks == MACH_SEND_INVALID_DEST) || (ks == MACH_SEND_TIMED_OUT))
+                       {
+                               /* clean up */
+                               mach_msg_destroy(&(reply->head));
+                       }
 
-               free(request);
+                       free(request);
+               });
        }
 }
 
@@ -925,7 +916,7 @@ __asl_server_message
 
        uid = (uid_t)-1;
        gid = (gid_t)-1;
-       pid = (gid_t)-1;
+       pid = (pid_t)-1;
        audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
 
        client = MACH_PORT_NULL;
@@ -941,8 +932,7 @@ __asl_server_message
        snprintf(tmp, sizeof(tmp), "%d", pid);
        asl_set(msg, ASL_KEY_PID, tmp);
 
-       /* verify and enqueue for processing */
-       asl_enqueue_message(SOURCE_ASL_MESSAGE, NULL, msg);
+       dispatch_async(global.work_queue, ^{ process_message(msg, SOURCE_ASL_MESSAGE); });
 
        return KERN_SUCCESS;
 }
@@ -1002,7 +992,7 @@ __asl_server_create_aux_link
 
        uid = (uid_t)-1;
        gid = (gid_t)-1;
-       pid = (gid_t)-1;
+       pid = (pid_t)-1;
        audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
 
        client = MACH_PORT_NULL;
@@ -1065,8 +1055,11 @@ __asl_server_register_direct_watch
 )
 {
        uint16_t p16 = port;
+       pid_t pid = (pid_t)-1;
+
+       audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
 
-       asldebug("__asl_server_register_direct_watch: %hu\n", ntohs(p16));
+       asldebug("__asl_server_register_direct_watch: pid %u port %hu\n", pid, ntohs(p16));
 
        register_direct_watch(p16);
 
index 664293625d09ddb5003f8abc48977263d1de983e..fddf3683a2eab09f511cc2bd478c06171c99b96e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #define forever for(;;)
 
 #define MY_ID "klog_in"
-#define MAXLINE 4096
+#define BUFF_SIZE 4096
 
-static int kx = 0;
-static char kline[MAXLINE + 1];
+static char inbuf[BUFF_SIZE];
+static int bx;
+static int kfd = -1;
+static dispatch_source_t in_src;
+static dispatch_queue_t in_queue;
 
-aslmsg
-klog_in_acceptmsg(int fd)
+void
+klog_in_acceptdata(int fd)
 {
-       int n;
-       char c;
+       ssize_t len;
+       uint32_t i;
+       char *p, *q;
+       aslmsg m;
 
-       n = read(fd, &c, 1);
+       len = read(fd, inbuf + bx, BUFF_SIZE - bx);
+       if (len <= 0) return;
 
-       while ((n == 1) && (c != '\n'))
+       p = inbuf;
+       q = p + bx;
+
+       for (i = 0; i < len; i++, q++)
        {
-               if (kx < MAXLINE) kline[kx++] = c;
-               n = read(fd, &c, 1);
+               if (*q == '\n')
+               {
+                       *q = '\0';
+                       m = asl_input_parse(p, q - p, NULL, SOURCE_KERN);
+                       dispatch_async(global.work_queue, ^{ process_message(m, SOURCE_KERN); });
+                       p = q + 1;
+               }
        }
 
-       if (kx == 0) return NULL;
-
-       n = kx - 1;
-       kline[kx] = '\0';
-       kx = 0;
-
-       return asl_input_parse(kline, n, NULL, SOURCE_KERN);
+       if (p != inbuf)
+       {
+               memmove(inbuf, p, BUFF_SIZE - bx - 1);
+               bx = q - p;
+       }
 }
 
 int
-klog_in_init(void)
+klog_in_init()
 {
+       static dispatch_once_t once;
+
+       dispatch_once(&once, ^{
+               in_queue = dispatch_queue_create(MY_ID, NULL);
+       });
+
        asldebug("%s: init\n", MY_ID);
-       if (global.kfd >= 0) return global.kfd;
+       if (kfd >= 0) return 0;
 
-       global.kfd = open(_PATH_KLOG, O_RDONLY, 0);
-       if (global.kfd < 0)
+       kfd = open(_PATH_KLOG, O_RDONLY, 0);
+       if (kfd < 0)
        {
                asldebug("%s: couldn't open %s: %s\n", MY_ID, _PATH_KLOG, strerror(errno));
                return -1;
        }
 
-       if (fcntl(global.kfd, F_SETFL, O_NONBLOCK) < 0)
+       if (fcntl(kfd, F_SETFL, O_NONBLOCK) < 0)
        {
-               close(global.kfd);
-               global.kfd = -1;
-               asldebug("%s: couldn't set O_NONBLOCK for fd %d (%s): %s\n", MY_ID, global.kfd, _PATH_KLOG, strerror(errno));
+               close(kfd);
+               kfd = -1;
+               asldebug("%s: couldn't set O_NONBLOCK for fd %d (%s): %s\n", MY_ID, kfd, _PATH_KLOG, strerror(errno));
                return -1;
        }
 
-       return aslevent_addfd(SOURCE_KERN, global.kfd, ADDFD_FLAGS_LOCAL, klog_in_acceptmsg, NULL, NULL);
+       in_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)kfd, 0, in_queue);
+       dispatch_source_set_event_handler(in_src, ^{ klog_in_acceptdata(kfd); });
+
+       dispatch_resume(in_src);
+       return 0;
 }
 
 int
 klog_in_close(void)
 {
-       if (global.kfd < 0) return 1;
+       if (kfd < 0) return 1;
+
+       dispatch_source_cancel(in_src);
+       dispatch_release(in_src);
+       in_src = NULL;
 
-       aslevent_removefd(global.kfd);
-       close(global.kfd);
-       global.kfd = -1;
+       close(kfd);
+       kfd = -1;
 
        return 0;
 }
index ad563a55ac65213018e657affa3de2426cc56ed0..945695f63d53e664fef1822c315b0a9ae3fbb13d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -38,8 +38,6 @@
 #include <netdb.h>
 #include <pthread.h>
 #include <notify.h>
-#include <asl_core.h>
-#include "asl_memory.h"
 #include "daemon.h"
 
 #define forever for(;;)
@@ -65,6 +63,10 @@ static int rfd4 = -1;
 static int rfd6 = -1;
 static int rfdl = -1;
 
+static dispatch_source_t in_src_local;
+static dispatch_source_t in_src_tcp;
+static dispatch_queue_t in_queue;
+
 #ifdef NSS32 
 typedef uint32_t notify_state_t;
 extern int notify_set_state(int, notify_state_t);
@@ -117,7 +119,7 @@ remote_db_stats(uint32_t sel)
 void
 session(void *x)
 {
-       int i, s, wfd, status, pfmt, watch, wtoken, nfd, do_prompt, filter;
+       int i, s, wfd, status, pfmt, watch, wtoken, nfd, do_prompt;
        aslresponse res;
        asl_search_result_t ql;
        uint32_t outlen;
@@ -126,9 +128,8 @@ session(void *x)
        asl_msg_t *qlq[1];
        char str[1024], *p, *qs, *out;
        ssize_t len;
-       fd_set readfds;
+       fd_set readfds, errfds;
        uint64_t low_id, high_id;
-       notify_state_t nstate;
        uint32_t dbselect, flags;
        session_args_t *sp;
 
@@ -139,6 +140,9 @@ session(void *x)
        flags = sp->flags;
        free(x);
 
+       asldebug("%s %d: starting interactive session for %ssocket %d\n", MY_ID, s, (flags & SESSION_FLAGS_LOCKDOWN) ? "lockdown " : "", s);
+
+       do_prompt = 1;
        watch = WATCH_OFF;
        wfd = -1;
        wtoken = -1;
@@ -155,7 +159,7 @@ session(void *x)
        query = NULL;
        memset(&ql, 0, sizeof(asl_search_result_t));
 
-       snprintf(str, sizeof(str) - 1, "\n========================\nASL is here to serve you\n");
+       snprintf(str, sizeof(str), "\n========================\nASL is here to serve you\n");
        if (write(s, str, strlen(str)) < 0)
        {
                close(s);
@@ -163,21 +167,22 @@ session(void *x)
                return;
        }
 
-       do_prompt = 1;
-
        forever
        {
-               if (do_prompt > 0)
+               if (((flags & SESSION_FLAGS_LOCKDOWN) == 0) && (do_prompt > 0))
                {
-                       snprintf(str, sizeof(str) - 1, "> ");
+                       snprintf(str, sizeof(str), "> ");
                        SESSION_WRITE(s, str);
                }
 
                do_prompt = 1;
+
                memset(str, 0, sizeof(str));
 
                FD_ZERO(&readfds);
                FD_SET(s, &readfds);
+               FD_ZERO(&errfds);
+               FD_SET(s, &errfds);
                nfd = s;
 
                if (wfd != -1)
@@ -186,17 +191,33 @@ session(void *x)
                        if (wfd > nfd) nfd = wfd;
                }
 
-               status = select(nfd + 1, &readfds, NULL, NULL, NULL);
+               status = select(nfd + 1, &readfds, NULL, &errfds, NULL);
+               if (status == 0) continue;
+               if (status < 0)
+               {
+                       asldebug("%s %d: select %d %s\n", MY_ID, s, errno, strerror(errno));
+                       goto exit_session;
+               }
+
+               if (FD_ISSET(s, &errfds))
+               {
+                       asldebug("%s %d: error on socket %d\n", MY_ID, s, s);
+                       goto exit_session;
+               }
 
                if ((wfd != -1) && (FD_ISSET(wfd, &readfds)))
                {
-                       len = read(wfd, &i, sizeof(int));
+                       (void)read(wfd, &i, sizeof(int));
                }
 
                if (FD_ISSET(s, &readfds))
                {
                        len = read(s, str, sizeof(str) - 1);
-                       if (len <= 0) goto exit_session;
+                       if (len <= 0)
+                       {
+                               asldebug("%s %d: read error on socket %d: %d %s\n", MY_ID, s, s, errno, strerror(errno));
+                               goto exit_session;
+                       }
 
                        while ((len > 1) && ((str[len - 1] == '\n') || (str[len - 1] == '\r')))
                        {
@@ -206,7 +227,7 @@ session(void *x)
 
                        if ((!strcmp(str, "q")) || (!strcmp(str, "quit")) || (!strcmp(str, "exit")))
                        {
-                               snprintf(str, sizeof(str) - 1, "Goodbye\n");
+                               snprintf(str, sizeof(str), "Goodbye\n");
                                write(s, str, strlen(str));
                                close(s);
                                s = -1;
@@ -215,55 +236,49 @@ session(void *x)
 
                        if ((!strcmp(str, "?")) || (!strcmp(str, "help")))
                        {
-                               snprintf(str, sizeof(str) - 1, "Commands\n");
-                               SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    quit                 exit session\n");
-                               SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    select [val]         get [set] current database\n");
+                               snprintf(str, sizeof(str), "Commands\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "                         val must be \"file\", \"mem\", or \"mini\"\n");
+                               snprintf(str, sizeof(str), "    quit                 exit session\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    file [on/off]        enable / disable file store\n");
+                               snprintf(str, sizeof(str), "    select [val]         get [set] current database\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    memory [on/off]      enable / disable memory store\n");
+                               snprintf(str, sizeof(str), "                         val must be \"file\", \"mem\", or \"mini\"\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    mini [on/off]        enable / disable mini memory store\n");
+                               snprintf(str, sizeof(str), "    file [on/off]        enable / disable file store\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    stats                database statistics\n");
+                               snprintf(str, sizeof(str), "    memory [on/off]      enable / disable memory store\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    flush                flush database\n");
+                               snprintf(str, sizeof(str), "    mini [on/off]        enable / disable mini memory store\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    dbsize [val]         get [set] database size (# of records)\n");
+                               snprintf(str, sizeof(str), "    stats                database statistics\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    filter [val]         get [set] current database filter\n");
+                               snprintf(str, sizeof(str), "    flush                flush database\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "                         [p]anic (emergency)  [a]lert  [c]ritical  [e]rror\n");
+                               snprintf(str, sizeof(str), "    dbsize [val]         get [set] database size (# of records)\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "                         [w]arning  [n]otice  [i]nfo  [d]ebug\n");
+                               snprintf(str, sizeof(str), "    watch                print new messages as they arrive\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    watch                print new messages as they arrive\n");
+                               snprintf(str, sizeof(str), "    stop                 stop watching for new messages\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    stop                 stop watching for new messages\n");
+                               snprintf(str, sizeof(str), "    raw                  use raw format for printing messages\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    raw                  use raw format for printing messages\n");
+                               snprintf(str, sizeof(str), "    std                  use standard format for printing messages\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    std                  use standard format for printing messages\n");
+                               snprintf(str, sizeof(str), "    *                    show all log messages\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    *                    show all log messages\n");
+                               snprintf(str, sizeof(str), "    * key val            equality search for messages (single key/value pair)\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    * key val            equality search for messages (single key/value pair)\n");
+                               snprintf(str, sizeof(str), "    * op key val         search for matching messages (single key/value pair)\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    * op key val         search for matching messages (single key/value pair)\n");
+                               snprintf(str, sizeof(str), "    * [op key val] ...   search for matching messages (multiple key/value pairs)\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "    * [op key val] ...   search for matching messages (multiple key/value pairs)\n");
+                               snprintf(str, sizeof(str), "                         operators:  =  <  >  ! (not equal)  T (key exists)  R (regex)\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "                         operators:  =  <  >  ! (not equal)  T (key exists)  R (regex)\n");
+                               snprintf(str, sizeof(str), "                         modifiers (must follow operator):\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "                         modifiers (must follow operator):\n");
+                               snprintf(str, sizeof(str), "                                 C=casefold  N=numeric  S=substring  A=prefix  Z=suffix\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "                                 C=casefold  N=numeric  S=substring  A=prefix  Z=suffix\n");
-                               SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "\n");
+                               snprintf(str, sizeof(str), "\n");
                                SESSION_WRITE(s, str);
                                continue;
                        }
@@ -284,10 +299,10 @@ session(void *x)
                                while ((*p == ' ') || (*p == '\t')) p++;
                                if (*p == '\0')
                                {
-                                       if (dbselect == 0) snprintf(str, sizeof(str) - 1, "no store\n");
-                                       else if (dbselect == DB_TYPE_FILE) snprintf(str, sizeof(str) - 1, "file store\n");
-                                       else if (dbselect == DB_TYPE_MEMORY) snprintf(str, sizeof(str) - 1, "memory store\n");
-                                       else if (dbselect == DB_TYPE_MINI) snprintf(str, sizeof(str) - 1, "mini memory store\n");
+                                       if (dbselect == 0) snprintf(str, sizeof(str), "no store\n");
+                                       else if (dbselect == DB_TYPE_FILE) snprintf(str, sizeof(str), "file store\n");
+                                       else if (dbselect == DB_TYPE_MEMORY) snprintf(str, sizeof(str), "memory store\n");
+                                       else if (dbselect == DB_TYPE_MINI) snprintf(str, sizeof(str), "mini memory store\n");
                                        SESSION_WRITE(s, str);
                                        continue;
                                }
@@ -296,7 +311,7 @@ session(void *x)
                                {
                                        if ((global.dbtype & DB_TYPE_FILE) == 0)
                                        {
-                                               snprintf(str, sizeof(str) - 1, "file database is not enabled\n");
+                                               snprintf(str, sizeof(str), "file database is not enabled\n");
                                                SESSION_WRITE(s, str);
                                                continue;
                                        }
@@ -307,7 +322,7 @@ session(void *x)
                                {
                                        if ((global.dbtype & DB_TYPE_MEMORY) == 0)
                                        {
-                                               snprintf(str, sizeof(str) - 1, "memory database is not enabled\n");
+                                               snprintf(str, sizeof(str), "memory database is not enabled\n");
                                                SESSION_WRITE(s, str);
                                                continue;
                                        }
@@ -320,12 +335,12 @@ session(void *x)
                                        {
                                                if (global.mini_db != NULL)
                                                {
-                                                       snprintf(str, sizeof(str) - 1, "mini memory database is enabled for disaster messages\n");
+                                                       snprintf(str, sizeof(str), "mini memory database is enabled for disaster messages\n");
                                                        SESSION_WRITE(s, str);
                                                }
                                                else
                                                {
-                                                       snprintf(str, sizeof(str) - 1, "mini memory database is not enabled\n");
+                                                       snprintf(str, sizeof(str), "mini memory database is not enabled\n");
                                                        SESSION_WRITE(s, str);
                                                        continue;
                                                }
@@ -335,12 +350,12 @@ session(void *x)
                                }
                                else
                                {
-                                       snprintf(str, sizeof(str) - 1, "unknown database type\n");
+                                       snprintf(str, sizeof(str), "unknown database type\n");
                                        SESSION_WRITE(s, str);
                                        continue;
                                }
 
-                               snprintf(str, sizeof(str) - 1, "OK\n");
+                               snprintf(str, sizeof(str), "OK\n");
                                SESSION_WRITE(s, str);
                                continue;
                        }
@@ -350,7 +365,7 @@ session(void *x)
                                while ((*p == ' ') || (*p == '\t')) p++;
                                if (*p == '\0')
                                {
-                                       snprintf(str, sizeof(str) - 1, "file database is %senabled\n", (global.dbtype & DB_TYPE_FILE) ? "" : "not ");
+                                       snprintf(str, sizeof(str), "file database is %senabled\n", (global.dbtype & DB_TYPE_FILE) ? "" : "not ");
                                        SESSION_WRITE(s, str);
                                        if ((global.dbtype & DB_TYPE_FILE) != 0) dbselect = DB_TYPE_FILE;
                                        continue;
@@ -359,7 +374,7 @@ session(void *x)
                                if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_FILE;
                                else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_FILE;
 
-                               snprintf(str, sizeof(str) - 1, "OK\n");
+                               snprintf(str, sizeof(str), "OK\n");
                                SESSION_WRITE(s, str);
                                continue;
                        }
@@ -369,7 +384,7 @@ session(void *x)
                                while ((*p == ' ') || (*p == '\t')) p++;
                                if (*p == '\0')
                                {
-                                       snprintf(str, sizeof(str) - 1, "memory database is %senabled\n", (global.dbtype & DB_TYPE_MEMORY) ? "" : "not ");
+                                       snprintf(str, sizeof(str), "memory database is %senabled\n", (global.dbtype & DB_TYPE_MEMORY) ? "" : "not ");
                                        SESSION_WRITE(s, str);
                                        if ((global.dbtype & DB_TYPE_MEMORY) != 0) dbselect = DB_TYPE_MEMORY;
                                        continue;
@@ -378,7 +393,7 @@ session(void *x)
                                if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_MEMORY;
                                else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_MEMORY;
 
-                               snprintf(str, sizeof(str) - 1, "OK\n");
+                               snprintf(str, sizeof(str), "OK\n");
                                SESSION_WRITE(s, str);
                                continue;
                        }
@@ -388,7 +403,7 @@ session(void *x)
                                while ((*p == ' ') || (*p == '\t')) p++;
                                if (*p == '\0')
                                {
-                                       snprintf(str, sizeof(str) - 1, "mini database is %senabled\n", (global.dbtype & DB_TYPE_MINI) ? "" : "not ");
+                                       snprintf(str, sizeof(str), "mini database is %senabled\n", (global.dbtype & DB_TYPE_MINI) ? "" : "not ");
                                        SESSION_WRITE(s, str);
                                        if ((global.dbtype & DB_TYPE_MINI) != 0) dbselect = DB_TYPE_MINI;
                                        continue;
@@ -397,7 +412,7 @@ session(void *x)
                                if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_MINI;
                                else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_MINI;
 
-                               snprintf(str, sizeof(str) - 1, "OK\n");
+                               snprintf(str, sizeof(str), "OK\n");
                                SESSION_WRITE(s, str);
                                continue;
                        }
@@ -405,7 +420,7 @@ session(void *x)
                        {
                                if (dbselect == 0)
                                {
-                                       snprintf(str, sizeof(str) - 1, "no store\n");
+                                       snprintf(str, sizeof(str), "no store\n");
                                        SESSION_WRITE(s, str);
                                        continue;
                                }
@@ -414,7 +429,7 @@ session(void *x)
                                while ((*p == ' ') || (*p == '\t')) p++;
                                if (*p == '\0')
                                {
-                                       snprintf(str, sizeof(str) - 1, "DB size %u\n", remote_db_size(dbselect));
+                                       snprintf(str, sizeof(str), "DB size %u\n", remote_db_size(dbselect));
                                        SESSION_WRITE(s, str);
                                        continue;
                                }
@@ -422,79 +437,10 @@ session(void *x)
                                i = atoi(p);
                                remote_db_set_size(dbselect, i);
 
-                               snprintf(str, sizeof(str) - 1, "OK\n");
+                               snprintf(str, sizeof(str), "OK\n");
                                SESSION_WRITE(s, str);
                                continue;
                        }
-                       else if (!strncmp(str, "filter", 6))
-                       {
-                               p = str + 6;
-                               while ((*p == ' ') || (*p == '\t')) p++;
-                               if (*p == '\0')
-                               {
-                                       snprintf(str, sizeof(str) - 1, "%s%s%s%s%s%s%s%s\n", 
-                                                        (global.asl_log_filter & ASL_FILTER_MASK_EMERG) ? "p" : "", 
-                                                        (global.asl_log_filter & ASL_FILTER_MASK_ALERT) ? "a" : "", 
-                                                        (global.asl_log_filter & ASL_FILTER_MASK_CRIT) ? "c" : "", 
-                                                        (global.asl_log_filter & ASL_FILTER_MASK_ERR) ? "e" : "", 
-                                                        (global.asl_log_filter & ASL_FILTER_MASK_WARNING) ? "w" : "", 
-                                                        (global.asl_log_filter & ASL_FILTER_MASK_NOTICE) ? "n" : "", 
-                                                        (global.asl_log_filter & ASL_FILTER_MASK_INFO) ? "i" : "", 
-                                                        (global.asl_log_filter & ASL_FILTER_MASK_DEBUG) ? "d" : "");
-                                       SESSION_WRITE(s, str);
-                                       continue;
-                               }
-
-                               filter = 0;
-                               if ((*p >= '0') && (*p <= '7'))
-                               {
-                                       i = atoi(p);
-                                       filter = ASL_FILTER_MASK_UPTO(i);
-                               }
-                               else
-                               {
-                                       while (*p != '\0')
-                                       {
-                                               if ((*p == 'p') || (*p == 'P')) filter |= ASL_FILTER_MASK_EMERG;
-                                               else if ((*p == 'a') || (*p == 'A')) filter |= ASL_FILTER_MASK_ALERT;
-                                               else if ((*p == 'c') || (*p == 'C')) filter |= ASL_FILTER_MASK_CRIT;
-                                               else if ((*p == 'e') || (*p == 'E')) filter |= ASL_FILTER_MASK_ERR;
-                                               else if ((*p == 'w') || (*p == 'W')) filter |= ASL_FILTER_MASK_WARNING;
-                                               else if ((*p == 'n') || (*p == 'N')) filter |= ASL_FILTER_MASK_NOTICE;
-                                               else if ((*p == 'i') || (*p == 'I')) filter |= ASL_FILTER_MASK_INFO;
-                                               else if ((*p == 'd') || (*p == 'D')) filter |= ASL_FILTER_MASK_DEBUG;
-                                               p++;
-                                       }
-                               }
-
-                               status = notify_register_check(NOTIFY_SYSTEM_ASL_FILTER, &i);
-                               if (status != NOTIFY_STATUS_OK)
-                               {
-                                       snprintf(str, sizeof(str) - 1, "FAILED %d\n", status);
-                                       SESSION_WRITE(s, str);
-                               }
-                               else
-                               {
-                                       nstate = filter;
-                                       status = notify_set_state(i, nstate);
-                                       if (status != NOTIFY_STATUS_OK)
-                                       {
-                                               snprintf(str, sizeof(str) - 1, "FAILED %d\n", status);
-                                               SESSION_WRITE(s, str);
-                                               continue;
-                                       }
-
-                                       status = notify_post(NOTIFY_SYSTEM_ASL_FILTER);
-                                       notify_cancel(i);
-
-                                       global.asl_log_filter = filter;
-
-                                       snprintf(str, sizeof(str) - 1, "OK\n");
-                                       SESSION_WRITE(s, str);
-                               }
-
-                               continue;
-                       }
                        else if (!strcmp(str, "stop"))
                        {
                                if (watch != WATCH_OFF)
@@ -510,12 +456,12 @@ session(void *x)
                                        if (query != NULL) free(query);
                                        query = NULL;
 
-                                       snprintf(str, sizeof(str) - 1, "OK\n");
+                                       snprintf(str, sizeof(str), "OK\n");
                                        SESSION_WRITE(s, str);
                                        continue;
                                }
 
-                               snprintf(str, sizeof(str) - 1, "not watching!\n");
+                               snprintf(str, sizeof(str), "not watching!\n");
                                SESSION_WRITE(s, str);
                                continue;
                        }
@@ -531,9 +477,9 @@ session(void *x)
                        }
                        else if (!strcmp(str, "watch"))
                        {
-                               if (watch != WATCH_OFF)
+                               if (((flags & SESSION_FLAGS_LOCKDOWN) == 0) && (watch != WATCH_OFF))
                                {
-                                       snprintf(str, sizeof(str) - 1, "already watching!\n");
+                                       snprintf(str, sizeof(str), "already watching!\n");
                                        SESSION_WRITE(s, str);
                                        continue;
                                }
@@ -544,10 +490,10 @@ session(void *x)
                                }
                                else
                                {
-                                       status = notify_register_file_descriptor(ASL_DB_NOTIFICATION, &wfd, 0, &wtoken);
+                                       status = notify_register_file_descriptor(kNotifyASLDBUpdate, &wfd, 0, &wtoken);
                                        if (status != 0)
                                        {
-                                               snprintf(str, sizeof(str) - 1, "notify_register_file_descriptor failed: %d\n", status);
+                                               snprintf(str, sizeof(str), "notify_register_file_descriptor failed: %d\n", status);
                                                SESSION_WRITE(s, str);
                                                continue;
                                        }
@@ -555,7 +501,7 @@ session(void *x)
                                        watch = WATCH_RUN;
                                }
 
-                               snprintf(str, sizeof(str) - 1, "OK\n");
+                               snprintf(str, sizeof(str), "OK\n");
                                SESSION_WRITE(s, str);
                                do_prompt = 2;
                        }
@@ -597,9 +543,9 @@ session(void *x)
                        }
                        else
                        {
-                               snprintf(str, sizeof(str) - 1, "unrecognized command\n");
+                               snprintf(str, sizeof(str), "unrecognized command\n");
                                SESSION_WRITE(s, str);
-                               snprintf(str, sizeof(str) - 1, "enter \"help\" for help\n");
+                               snprintf(str, sizeof(str), "enter \"help\" for help\n");
                                SESSION_WRITE(s, str);
                                continue;
                        }
@@ -613,16 +559,12 @@ session(void *x)
                 * the initial messages are sent to PurpleConsole before setting 
                 * global.lockdown_session_fd to allow this query to complete before
                 * dbserver starts sending.  To prevent a race between this query and
-                * when the first message is sent by send_to_direct_watchers, we hold
-                * the work queue lock between the time of the query and the time that
-                * lockdown_session_fd is set.
+                * when messages are sent by send_to_direct_watchers, we  suspend the
+                * work queue here and resume it when lockdown_session_fd is set.
                 */
                if ((flags & SESSION_FLAGS_LOCKDOWN) && (watch == WATCH_RUN)) continue;
 
-               if (watch == WATCH_LOCKDOWN_START)
-               {
-                       pthread_mutex_lock(global.work_queue_lock);
-               }
+               if (watch == WATCH_LOCKDOWN_START) dispatch_suspend(global.work_queue);
 
                if (query != NULL)
                {
@@ -635,7 +577,7 @@ session(void *x)
 
                memset(&res, 0, sizeof(aslresponse));
                high_id = 0;
-               status = db_query(&ql, (aslresponse *)&res, low_id, 0, 0, &high_id, 0, 0);
+               (void)db_query(&ql, (aslresponse *)&res, low_id, 0, 0, &high_id, 0, 0);
 
                if ((watch == WATCH_RUN) && (high_id >= low_id)) low_id = high_id + 1;
 
@@ -643,7 +585,7 @@ session(void *x)
                {
                        if (watch == WATCH_OFF)
                        {
-                               snprintf(str, sizeof(str) - 1, "-nil-\n");
+                               snprintf(str, sizeof(str), "-nil-\n");
                                SESSION_WRITE(s, str);
                        }
                        else
@@ -655,7 +597,7 @@ session(void *x)
                {
                        if (watch == WATCH_RUN)
                        {
-                               snprintf(str, sizeof(str) - 1, "\n");
+                               snprintf(str, sizeof(str), "\n");
                                SESSION_WRITE(s, str);
                        }
 
@@ -664,22 +606,48 @@ session(void *x)
                        write(s, out, outlen);
                        free(out);
 
-                       snprintf(str, sizeof(str) - 1, "\n");
+                       snprintf(str, sizeof(str), "\n");
                        SESSION_WRITE(s, str);
                }
                else
                {
                        if (watch == WATCH_RUN)
                        {
-                               snprintf(str, sizeof(str) - 1, "\n");
+                               snprintf(str, sizeof(str), "\n");
                                SESSION_WRITE(s, str);
                        }
 
+                       snprintf(str, sizeof(str), "\n");
                        for (i = 0; i < res->count; i++)
                        {
+                               int wstatus;
+
                                out = asl_format_message(res->msg[i], ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &outlen);
-                               write(s, out, outlen);
+
+                               do
+                               {
+                                       int n = 0;
+
+                                       errno = 0;
+                                       wstatus = write(s, out, outlen);
+                                       if (wstatus < 0)
+                                       {
+                                               asldebug("%s %d: %d/%d write data failed: %d %s\n", MY_ID, s, i, res->count, errno, strerror(errno));
+                                               if (errno == EAGAIN)
+                                               {
+                                                       n++;
+                                                       if (n > 10) break;
+                                                       usleep(10000);
+                                               }
+                                               else
+                                               {
+                                                       goto exit_session;
+                                               }
+                                       }
+                               } while (errno == EAGAIN);
+
                                free(out);
+                               if (global.remote_delay_time > 0) usleep(global.remote_delay_time);
                        }
                }
 
@@ -691,21 +659,23 @@ session(void *x)
                        global.watchers_active++;
                        watch = WATCH_RUN;
 
-                       pthread_mutex_unlock(global.work_queue_lock);
+                       dispatch_resume(global.work_queue);
                }
        }
 
 exit_session:
 
+       asldebug("%s %d: terminating session for %ssocket %d\n", MY_ID, s, (flags & SESSION_FLAGS_LOCKDOWN) ? "lockdown " : "", s);
+
        if (s >= 0)
        {
                if (s == global.lockdown_session_fd) global.lockdown_session_fd = -1;
                if (global.watchers_active > 0) global.watchers_active--;
                close(s);
-               s = -1;
        }
 
-       if (watch != WATCH_OFF) notify_cancel(wtoken);
+       if (watch == WATCH_LOCKDOWN_START) dispatch_resume(global.work_queue);
+       if (wtoken >= 0) notify_cancel(wtoken);
        if (query != NULL) asl_msg_release(query);
        pthread_exit(NULL);
 }
@@ -714,7 +684,7 @@ aslmsg
 remote_acceptmsg(int fd, int tcp)
 {
        socklen_t fromlen;
-       int s, status, flags, v;
+       int s, flags, status, v;
        pthread_attr_t attr;
        pthread_t t;
        struct sockaddr_storage from;
@@ -842,7 +812,10 @@ remote_init_lockdown(void)
 
        chmod(SYSLOG_SOCK_PATH, 0666);
 
-       aslevent_addfd(SOURCE_SESSION, fd, 0, remote_acceptmsg_local, NULL, NULL);
+       in_src_local = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)fd, 0, in_queue);
+       dispatch_source_set_event_handler(in_src_local, ^{ remote_acceptmsg_local(fd); });
+       dispatch_resume(in_src_local);
+
        return fd;
 }
 
@@ -912,13 +885,22 @@ remote_init_tcp(int family)
                return -1;
        }
 
-       aslevent_addfd(SOURCE_SESSION, fd, 0, remote_acceptmsg_tcp, NULL, NULL);
+       in_src_tcp = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)fd, 0, in_queue);
+       dispatch_source_set_event_handler(in_src_tcp, ^{ remote_acceptmsg_tcp(fd); });
+       dispatch_resume(in_src_tcp);
+
        return fd;
 }
 
 int
 remote_init(void)
 {
+       static dispatch_once_t once;
+
+       dispatch_once(&once, ^{
+               in_queue = dispatch_queue_create(MY_ID, NULL);
+       });
+
        asldebug("%s: init\n", MY_ID);
 
 #ifdef LOCKDOWN
@@ -941,7 +923,6 @@ remote_close(void)
 {
        if (rfdl >= 0)
        {
-               aslevent_removefd(rfdl);
                close(rfdl);
        }
 
@@ -949,7 +930,6 @@ remote_close(void)
 
        if (rfd4 >= 0) 
        {
-               aslevent_removefd(rfd4);
                close(rfd4);
        }
 
@@ -957,7 +937,6 @@ remote_close(void)
 
        if (rfd6 >= 0)
        {
-               aslevent_removefd(rfd6);
                close(rfd6);
        }
 
@@ -969,6 +948,8 @@ remote_close(void)
 int
 remote_reset(void)
 {
+       return 0;
+
        remote_close();
        return remote_init();
 }
index c0b614928bd79cf32c25e48c92b36156952bbc7a..aa3ea22e652562a7f5f5bb1e161695dc66dbb025 100644 (file)
@@ -1,4 +1,4 @@
-.\"Copyright (c) 2004-2008 Apple Inc. All rights reserved.
+.\"Copyright (c) 2004-2011 Apple Inc. All rights reserved.
 .\"
 .\"@APPLE_LICENSE_HEADER_START@
 .\"
 .Op Fl d
 .Op Fl D
 .Op Fl m Ar mark_interval
-.Op Fl c Ar log_cutoff
 .Op Fl l Ar lib_path
 .Op Fl db_max Ar size
 .Op Fl utmp_ttl Ar time
-.Op Fl fs_ttl Ar time
 .Op Fl mps_limit Ar quota
 .Op Fl dup_delay Ar time
 .Op Fl module_name Li {0|1}
@@ -96,38 +94,6 @@ is specified with no arguments, mark messages will be written every 20 minutes.
 The 
 .Dq mark
 facility is disabled if the setting is zero minutes.
-.It Fl c
-Sets a cutoff filter for log priorities for messages to be retained in the log message data store.
-The value of 
-.Ar log_cutoff
-must be between 0 and 7, corresponding to log priorities LOG_EMERG or ASL_LEVEL_EMERG
-and LOG_DEBUG or ASL_LEVEL_DEBUG as defined in the 
-.Xr syslog 3
-and
-.Xr asl 3
-header files.
-Received messages with a priority or level value greater than the cutoff will not be saved in the data store.
-The default filter value is set to allow all message priorities.
-Message filtering is primarily specified by the rules in the /etc/asl.conf file.
-However, if there are no matching rules for the ASL data store in the asl.conf file,
-then all messages that are allowed by the cutoff filter are saved.
-.Pp
-Note that a this filter value may be adjusted while
-.Nm
-is running using the
-.Nm syslog
-command-line utility.
-See the
-.Xr syslog 1
-manual.
-The filter may be adjusted using the
-.Dq -c
-option.
-.It Fl l
-Specifies an alternate path for loading plug-in modules.
-By default,
-.Nm
-checks for plug-in modules in the directory /usr/lib/asl.
 .It Fl db_max
 Sets the size limit in bytes for individual files in the data store.
 The default value for
@@ -146,13 +112,6 @@ Note that if archival is enabled (see the
 .Xr aslmanager 8
 manual), these messages will be copied to an archive
 after the regular time-to-live interval, but will persist in the data store until their own expiry time.
-.It Fl fs_ttl
-Sets the time-to-live in seconds for filesystem error messages generated by the kernel.
-The default is 31622400 seconds (approximately 1 year).
-As in the case of
-.Fl utmp_ttl ,
-if archival is enabled, these messages will be copied to an archive after the regular time-to-live
-interval but will persist in the data store until their own expiry time.
 .It Fl mps_limit
 Sets the per-process quota for messages per second allowed by
 .Nm .
index 43844f68507e83e0b563b9d45c44c5ee3f5c0da9..0d79fd88ece39b199f9de871d7737ce89c4c87f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -44,7 +44,9 @@
 #include <dlfcn.h>
 #include <libgen.h>
 #include <notify.h>
+#include <notify_keys.h>
 #include <utmpx.h>
+#include <vproc_priv.h>
 #include "daemon.h"
 
 #define SERVICE_NAME "com.apple.system.logger"
 #define SERVER_STATUS_ACTIVE 1
 #define SERVER_STATUS_ON_DEMAND 2
 
-#define DEFAULT_MARK_SEC 0
-#define DEFAULT_UTMP_TTL_SEC 31622400
-#define DEFAULT_FS_TTL_SEC 31622400
-#define DEFAULT_BSD_MAX_DUP_SEC 30
-#define DEFAULT_MPS_LIMIT 500
 #define BILLION 1000000000
 
 #define NOTIFY_DELAY 1
 
-#define NETWORK_CHANGE_NOTIFICATION "com.apple.system.config.network_change"
-
 #define streq(A,B) (strcmp(A,B)==0)
 #define forever for(;;)
 
-static uint64_t time_start = 0;
-static uint64_t mark_last = 0;
-static uint64_t ping_last = 0;
-static uint64_t time_last = 0;
-
 extern int __notify_78945668_info__;
 extern int _malloc_no_asl_log;
 
-static TAILQ_HEAD(ml, module_list) Moduleq;
-
 /* global */
 struct global_s global;
 
-/* Static Modules */
-int asl_in_init();
-int asl_in_reset();
-int asl_in_close();
-static int activate_asl_in = 1;
-
-int asl_action_init();
-int asl_action_reset();
-int asl_action_close();
-static int activate_asl_action = 1;
-
-int klog_in_init();
-int klog_in_reset();
-int klog_in_close();
+/* Input Modules */
+int klog_in_init(void);
+int klog_in_reset(void);
+int klog_in_close(void);
 static int activate_klog_in = 1;
 
-int bsd_in_init();
-int bsd_in_reset();
-int bsd_in_close();
+int bsd_in_init(void);
+int bsd_in_reset(void);
+int bsd_in_close(void);
 static int activate_bsd_in = 1;
 
-int bsd_out_init();
-int bsd_out_reset();
-int bsd_out_close();
+int udp_in_init(void);
+int udp_in_reset(void);
+int udp_in_close(void);
+static int activate_udp_in = 1;
+
+/* Output Modules */
+int bsd_out_init(void);
+int bsd_out_reset(void);
+int bsd_out_close(void);
 static int activate_bsd_out = 1;
 
-int remote_init();
-int remote_reset();
-int remote_close();
-static int activate_remote = 0;
+int asl_action_init(void);
+int asl_action_reset(void);
+int asl_action_close(void);
+static int activate_asl_action = 1;
 
-int udp_in_init();
-int udp_in_reset();
-int udp_in_close();
-static int activate_udp_in = 1;
+/* Interactive Module */
+int remote_init(void);
+int remote_reset(void);
+int remote_close(void);
+static int remote_enabled = 0;
 
 extern void database_server();
-extern void output_worker();
-extern void launchd_drain();
-extern void bsd_flush_duplicates(time_t now);
-extern void bsd_close_idle_files(time_t now);
 
-/*
- * Module approach: only one type of module.  This module may implement
- * the set of functions necessary for any of the functions (input, output,
- * etc.)  Prior to using the modules, dlsym() is consulted to see what it
- * implements.
- */
-
-static int
-static_modules()
+static void
+init_modules()
 {
-       struct module_list *tmp;
+       module_t *m_klog_in, *m_bsd_in, *m_bsd_out, *m_udp_in;
+       module_t *m_asl, *m_remote;
 
-       /*
-        * The order of these initializations is important.
-        * When messages are sent to output modules, they are
-        * sent in the same order as these initializations.
-        * asl_action may add modify messages, for example to
-        * add access controls, so it must come first.
-        */
-       if (activate_asl_action != 0)
+       /* ASL module (configured by /etc/asl.conf) */
+       m_asl = (module_t *)calloc(1, sizeof(module_t));
+       if (m_asl == NULL)
        {
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL) return 1;
-
-               tmp->name = strdup("asl_action");
-               if (tmp->name == NULL)
-               {
-                       free(tmp);
-                       return 1;
-               }
-
-               tmp->module = NULL;
-               tmp->init = asl_action_init;
-               tmp->reset = asl_action_reset;
-               tmp->close = asl_action_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
+               asldebug("alloc failed (init_modules asl_action)\n");
+               exit(1);
        }
 
-       if (activate_asl_in != 0)
-       {
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL) return 1;
+       m_asl->name = "asl_action";
+       m_asl->enabled = activate_asl_action;
+       m_asl->init = asl_action_init;
+       m_asl->reset = asl_action_reset;
+       m_asl->close = asl_action_close;
 
-               tmp->name = strdup("asl_in");
-               if (tmp->name == NULL)
-               {
-                       free(tmp);
-                       return 1;
-               }
-
-               tmp->module = NULL;
-               tmp->init = asl_in_init;
-               tmp->reset = asl_in_reset;
-               tmp->close = asl_in_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
-       }
+       if (m_asl->enabled) m_asl->init();
 
-       if (activate_klog_in != 0)
+       /* BSD output module (configured by /etc/syslog.conf) */
+       m_bsd_out = (module_t *)calloc(1, sizeof(module_t));
+       if (m_bsd_out == NULL)
        {
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL) return 1;
-
-               tmp->name = strdup("klog_in");
-               if (tmp->name == NULL)
-               {
-                       free(tmp);
-                       return 1;
-               }
-
-               tmp->module = NULL;
-               tmp->init = klog_in_init;
-               tmp->reset = klog_in_reset;
-               tmp->close = klog_in_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
+               asldebug("alloc failed (init_modules bsd_out)\n");
+               exit(1);
        }
 
-       if (activate_bsd_in != 0)
-       {
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL) return 1;
-
-               tmp->name = strdup("bsd_in");
-               if (tmp->name == NULL)
-               {
-                       free(tmp);
-                       return 1;
-               }
-
-               tmp->module = NULL;
-               tmp->init = bsd_in_init;
-               tmp->reset = bsd_in_reset;
-               tmp->close = bsd_in_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
-       }
+       m_bsd_out->name = "bsd_out";
+       m_bsd_out->enabled = activate_bsd_out;
+       m_bsd_out->init = bsd_out_init;
+       m_bsd_out->reset = bsd_out_reset;
+       m_bsd_out->close = bsd_out_close;
 
-       if (activate_bsd_out != 0)
+       if (m_bsd_out->enabled)
        {
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL) return 1;
-
-               tmp->name = strdup("bsd_out");
-               if (tmp->name == NULL)
-               {
-                       free(tmp);
-                       return 1;
-               }
-
-               tmp->module = NULL;
-               tmp->init = bsd_out_init;
-               tmp->reset = bsd_out_reset;
-               tmp->close = bsd_out_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
+               m_bsd_out->init();
+               global.bsd_out_enabled = 1;
        }
 
-       if (activate_remote != 0)
+       /* kernel input module */
+       m_klog_in = (module_t *)calloc(1, sizeof(module_t));
+       if (m_klog_in == NULL)
        {
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL) return 1;
-
-               tmp->name = strdup("remote");
-               if (tmp->name == NULL)
-               {
-                       free(tmp);
-                       return 1;
-               }
-
-               tmp->module = NULL;
-               tmp->init = remote_init;
-               tmp->reset = remote_reset;
-               tmp->close = remote_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
+               asldebug("alloc failed (init_modules klog_in)\n");
+               exit(1);
        }
 
-       if (activate_udp_in != 0)
-       {
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL) return 1;
+       m_klog_in->name = "klog_in";
+       m_klog_in->enabled = activate_klog_in;
+       m_klog_in->init = klog_in_init;
+       m_klog_in->reset = klog_in_reset;
+       m_klog_in->close = klog_in_close;
 
-               tmp->name = strdup("udp_in");
-               if (tmp->name == NULL)
-               {
-                       free(tmp);
-                       return 1;
-               }
+       if (m_klog_in->enabled) m_klog_in->init();
 
-               tmp->module = NULL;
-               tmp->init = udp_in_init;
-               tmp->reset = udp_in_reset;
-               tmp->close = udp_in_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
+       /* BSD (UNIX domain socket) input module */
+       m_bsd_in = (module_t *)calloc(1, sizeof(module_t));
+       if (m_bsd_in == NULL)
+       {
+               asldebug("alloc failed (init_modules bsd_in)\n");
+               exit(1);
        }
 
-       return 0;
-}
+       m_bsd_in->name = "bsd_in";
+       m_bsd_in->enabled = activate_bsd_in;
+       m_bsd_in->init = bsd_in_init;
+       m_bsd_in->reset = bsd_in_reset;
+       m_bsd_in->close = bsd_in_close;
 
-/*
- * Loads all the modules.  This DOES NOT call the modules initializer
- * functions.  It simply scans the modules directory looking for modules
- * and loads them.  This does not mean the module will be used.  
- */
-static int
-load_modules(const char *mp)
-{
-       DIR *d;
-       struct dirent *de;
-       struct module_list *tmp;
-       void *c, *bn;
-       char *modulepath = NULL;
-
-       d = opendir(mp);
-       if (d == NULL) return -1;
+       if (m_bsd_in->enabled) m_bsd_in->init();
 
-       while (NULL != (de = readdir(d)))
+       /* network (syslog protocol) input module */
+       m_udp_in = (module_t *)calloc(1, sizeof(module_t));
+       if (m_udp_in == NULL)
        {
-               if (de->d_name[0] == '.') continue;
-
-               /* Must have ".so" in the name" */
-               if (!strstr(de->d_name, ".so")) continue;
-
-               asprintf(&modulepath, "%s/%s", mp, de->d_name);
-               if (!modulepath) continue;
+               asldebug("alloc failed (init_modules udp_in)\n");
+               exit(1);
+       }
 
-               c = dlopen(modulepath, RTLD_LOCAL);
-               if (c == NULL)
-               {
-                       free(modulepath);
-                       continue;
-               }
+       m_udp_in->name = "udp_in";
+       m_udp_in->enabled = activate_udp_in;
+       m_udp_in->init = udp_in_init;
+       m_udp_in->reset = udp_in_reset;
+       m_udp_in->close = udp_in_close;
 
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL)
-               {
-                       free(modulepath);
-                       dlclose(c);
-                       continue;
-               }
+       if (m_udp_in->enabled) m_udp_in->init();
 
-               bn = basename(modulepath);
-               tmp->name = strdup(bn);
-               if (tmp->name == NULL)
-               {
-                       free(tmp);
-                       return 1;
-               }
+       /* remote (iOS support) module */
+       m_remote = (module_t *)calloc(1, sizeof(module_t));
+       if (m_remote == NULL)
+       {
+               asldebug("alloc failed (init_modules remote)\n");
+               exit(1);
+       }
 
-               tmp->module = c;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
+       m_remote->name = "remote";
+       m_remote->enabled = remote_enabled;
+       m_remote->init = remote_init;
+       m_remote->reset = remote_reset;
+       m_remote->close = remote_close;
 
-               tmp->init = dlsym(tmp->module, "aslmod_init");
-               tmp->reset = dlsym(tmp->module, "aslmod_reset");
-               tmp->close = dlsym(tmp->module, "aslmod_close");
+       if (m_remote->enabled) m_remote->init();
 
-               free(modulepath);
+       /* save modules in global.module array */
+       global.module_count = 6;
+       global.module = (module_t **)calloc(global.module_count, sizeof(module_t *));
+       if (global.module == NULL)
+       {
+               asldebug("alloc failed (init_modules)\n");
+               exit(1);
        }
 
-       closedir(d);
-
-       return 0;
+       global.module[0] = m_asl;
+       global.module[1] = m_bsd_out;
+       global.module[2] = m_klog_in;
+       global.module[3] = m_bsd_in;
+       global.module[4] = m_udp_in;
+       global.module[5] = m_remote;
 }
 
 static void
@@ -347,6 +231,9 @@ writepid(int *first)
 {
        struct stat sb;
        FILE *fp;
+       pid_t pid = getpid();
+
+       asldebug("\nsyslogd %d start\n", pid);
 
        if (first != NULL)
        {
@@ -361,168 +248,13 @@ writepid(int *first)
        fp = fopen(_PATH_PIDFILE, "w");
        if (fp != NULL)
        {
-               fprintf(fp, "%d\n", getpid());
+               fprintf(fp, "%d\n", pid);
                fclose(fp);
        }
 }
 
-static void
-closeall(void)
-{
-       int i;
-
-       for (i = getdtablesize() - 1; i >= 0; i--) close(i);
-
-       open("/dev/null", O_RDWR, 0);
-       dup(0);
-       dup(0);
-}
-
-static void
-detach(void)
-{
-       signal(SIGINT, SIG_IGN);
-       signal(SIGPIPE, SIG_IGN);
-       setsid();
-}
-
-static void
-catch_sighup(int x)
-{
-       global.reset = RESET_CONFIG;
-}
-
-static void
-catch_siginfo(int x)
-{
-       global.reset = RESET_NETWORK;
-}
-
-static void
-send_reset(void)
-{
-       struct module_list *mod;
-
-       for (mod = Moduleq.tqh_first; mod != NULL; mod = mod->entries.tqe_next)
-       {
-               if (mod->reset != NULL) mod->reset();
-       }
-}
-
-/*
- * perform timed activities and set next run-loop timeout
- */
-static void
-timed_events(struct timeval **run)
-{
-       time_t now, delta, t;
-       static struct timeval next;
-
-       now = time(NULL);
-
-       *run = NULL;
-       next.tv_sec = 0;
-       next.tv_usec = 0;
-
-       if (time_start == 0)
-       {
-               /* startup */
-               time_start = now;
-               time_last = now;
-               mark_last = now;
-               ping_last = now;
-       }
-
-       /*
-        * At startup, we try sending a notification once a second.
-        * Once it succeeds, we set the Libc global __notify_78945668_info__ to 0
-        * which lets Libc's localtime calculations use notifyd to invalidate
-        * cached timezones.  This prevents a deadlock in localtime. 
-        */
-       if (__notify_78945668_info__ < 0)
-       {
-               if (notify_post("com.apple.system.syslogd") == NOTIFY_STATUS_OK) __notify_78945668_info__ = 0;
-               else next.tv_sec = 1;
-       }
-
-       if (time_last > now)
-       {
-               /*
-                * Despite Albert Einstein's assurance, time has gone backward.
-                * Reset "last" times to current time.
-                */
-               time_last = now;
-               mark_last = now;
-               ping_last = now;
-       }
-
-       /*
-        * Tickle bsd_out module to flush duplicates.
-        */
-       if (global.bsd_flush_time > 0)
-       {
-               bsd_flush_duplicates(now);
-               bsd_close_idle_files(now);
-               if (global.bsd_flush_time > 0)
-               {
-                       if (next.tv_sec == 0) next.tv_sec = global.bsd_flush_time;
-                       else if (global.bsd_flush_time < next.tv_sec) next.tv_sec = global.bsd_flush_time;
-               }
-       }
-
-       /*
-        * Tickle asl_store to sweep file cache
-        */
-       if (global.asl_store_ping_time > 0)
-       {
-               delta = now - ping_last; 
-               if (delta >= global.asl_store_ping_time)
-               {
-                       db_ping_store();
-                       bsd_close_idle_files(now);
-                       ping_last = now;
-                       t = global.asl_store_ping_time;
-               }
-               else
-               {
-                       t = global.asl_store_ping_time - delta;
-               }
-
-               if (next.tv_sec == 0) next.tv_sec = t;
-               else if (t < next.tv_sec) next.tv_sec = t;
-       }
-
-       /*
-        * Send MARK
-        */
-       if (global.mark_time > 0)
-       {
-               delta = now - mark_last; 
-               if (delta >= global.mark_time)
-               {
-                       asl_mark();
-                       mark_last = now;
-                       t = global.mark_time;
-               }
-               else
-               {
-                       t = global.mark_time - delta;
-               }
-
-               if (next.tv_sec == 0) next.tv_sec = t;
-               else if (t < next.tv_sec) next.tv_sec = t;
-       }
-
-       /*
-        * set output timeout parameter if runloop needs to have a timer
-        */
-       if (next.tv_sec > 0) *run = &next;
-
-       time_last = now;
-}
-
 void
-init_config()
+launch_config()
 {
        launch_data_t tmp, pdict;
        kern_return_t status;
@@ -533,74 +265,52 @@ init_config()
 
        if (global.launch_dict == NULL)
        {
-               fprintf(stderr, "%d launchd checkin failed\n", getpid());
+               asldebug("%d launchd checkin failed\n", getpid());
                exit(1);
        }
 
        tmp = launch_data_dict_lookup(global.launch_dict, LAUNCH_JOBKEY_MACHSERVICES);
        if (tmp == NULL)
        {
-               fprintf(stderr, "%d launchd lookup of LAUNCH_JOBKEY_MACHSERVICES failed\n", getpid());
+               asldebug("%d launchd lookup of LAUNCH_JOBKEY_MACHSERVICES failed\n", getpid());
                exit(1);
        }
 
        pdict = launch_data_dict_lookup(tmp, SERVICE_NAME);
        if (pdict == NULL)
        {
-               fprintf(stderr, "%d launchd lookup of SERVICE_NAME failed\n", getpid());
+               asldebug("%d launchd lookup of SERVICE_NAME failed\n", getpid());
                exit(1);
        }
 
        global.server_port = launch_data_get_machport(pdict);
 
-       /* port for receiving internal messages */
-       status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &(global.self_port));
-       if (status != KERN_SUCCESS)
-       {
-               fprintf(stderr, "mach_port_allocate self_port failed: %d", status);
-               exit(1);
-       }
-
-       status = mach_port_insert_right(mach_task_self(), global.self_port, global.self_port, MACH_MSG_TYPE_MAKE_SEND);
-       if (status != KERN_SUCCESS)
-       {
-               fprintf(stderr, "Can't make send right for self_port: %d\n", status);
-               exit(1);
-       }
-
        /* port for receiving MACH_NOTIFY_DEAD_NAME notifications */
        status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &(global.dead_session_port));
        if (status != KERN_SUCCESS)
        {
-               fprintf(stderr, "mach_port_allocate dead_session_port failed: %d", status);
+               asldebug("mach_port_allocate dead_session_port failed: %d", status);
                exit(1);
        }
 
        status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &(global.listen_set));
        if (status != KERN_SUCCESS)
        {
-               fprintf(stderr, "mach_port_allocate listen_set failed: %d", status);
+               asldebug("mach_port_allocate listen_set failed: %d", status);
                exit(1);
        }
 
        status = mach_port_move_member(mach_task_self(), global.server_port, global.listen_set);
        if (status != KERN_SUCCESS)
        {
-               fprintf(stderr, "mach_port_move_member server_port failed: %d", status);
-               exit(1);
-       }
-
-       status = mach_port_move_member(mach_task_self(), global.self_port, global.listen_set);
-       if (status != KERN_SUCCESS)
-       {
-               fprintf(stderr, "mach_port_move_member self_port failed: %d", status);
+               asldebug("mach_port_move_member server_port failed: %d", status);
                exit(1);
        }
 
        status = mach_port_move_member(mach_task_self(), global.dead_session_port, global.listen_set);
        if (status != KERN_SUCCESS)
        {
-               fprintf(stderr, "mach_port_move_member dead_session_port failed (%u)", status);
+               asldebug("mach_port_move_member dead_session_port failed (%u)", status);
                exit(1);
        }
 }
@@ -611,7 +321,7 @@ config_debug(int enable, const char *path)
        OSSpinLockLock(&global.lock);
 
        global.debug = enable;
-       if (global.debug_file != NULL) free(global.debug_file);
+       free(global.debug_file);
        global.debug_file = NULL;
        if (path != NULL) global.debug_file = strdup(path);
 
@@ -672,7 +382,7 @@ write_boot_log(int first)
                snprintf(buf, sizeof(buf), "%u", getpid());
                asl_set(msg, ASL_KEY_PID, buf);
                asl_set(msg, ASL_KEY_MSG, "--- syslogd restarted ---");
-               asl_enqueue_message(SOURCE_INTERNAL, NULL, msg);
+               dispatch_async(global.work_queue, ^{ process_message(msg, SOURCE_INTERNAL); });
                return;
        }
 
@@ -711,23 +421,17 @@ write_boot_log(int first)
        snprintf(buf, sizeof(buf), "%u%s", (unsigned int)utx.ut_tv.tv_usec, (utx.ut_tv.tv_usec == 0) ? "" : "000");
        asl_set(msg, ASL_KEY_TIME_NSEC, buf);
 
-       asl_enqueue_message(SOURCE_INTERNAL, NULL, msg);
+       dispatch_async(global.work_queue, ^{ process_message(msg, SOURCE_INTERNAL); });
 }
 
 int
 main(int argc, const char *argv[])
 {
-       struct module_list *mod;
-       fd_set rd, wr, ex, kern;
-       int32_t fd, i, max, status, daemonize;
-       const char *mp;
-       struct timeval *runloop_timer, zto;
-       pthread_attr_t attr;
-       pthread_t t;
-       int network_change_token;
+       int32_t i;
+       int network_change_token, asl_db_token;
        char tstr[32];
        time_t now;
-       int first_syslogs_start = 1;
+       int first_syslogd_start = 1;
 
        /* Set I/O policy */
        setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_PASSIVE);
@@ -737,42 +441,21 @@ main(int argc, const char *argv[])
        global.db_lock = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t));
        pthread_mutex_init(global.db_lock, NULL);
 
-       global.work_queue_lock = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t));
-       pthread_mutex_init(global.work_queue_lock, NULL);
-
-       pthread_cond_init(&global.work_queue_cond, NULL);
-
-       global.work_queue = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t));
+       /*
+        * Create work queue, but suspend until output modules are initialized.
+        */
+       global.work_queue = dispatch_queue_create("Work Queue", NULL);
+       dispatch_suspend(global.work_queue);
 
-       global.asl_log_filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG);
-       global.db_file_max = 16384000;
-       global.db_memory_max = 8192;
-       global.db_mini_max = 256;
-       global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC;
-       global.utmp_ttl = DEFAULT_UTMP_TTL_SEC;
-       global.fs_ttl = DEFAULT_FS_TTL_SEC;
-       global.mps_limit = DEFAULT_MPS_LIMIT;
-       global.kfd = -1;
        global.lockdown_session_fd = -1;
 
-#ifdef CONFIG_MAC
-       global.dbtype = DB_TYPE_FILE;
-       global.db_file_max = 25600000;
-       global.asl_store_ping_time = 150;
-#endif
+       init_globals();
 
 #ifdef CONFIG_IPHONE
-       global.dbtype = DB_TYPE_MINI;
-       activate_remote = 1;
+       remote_enabled = 1;
        activate_bsd_out = 0;
 #endif
 
-       mp = _PATH_MODULE_LIB;
-       daemonize = 0;
-       __notify_78945668_info__ = 0xf0000000;
-       zto.tv_sec = 0;
-       zto.tv_usec = 0;
-
        /* prevent malloc from calling ASL on error */
        _malloc_no_asl_log = 1;
 
@@ -797,7 +480,7 @@ main(int argc, const char *argv[])
                                else if (streq(argv[i], "iphone"))
                                {
                                        global.dbtype = DB_TYPE_MINI;
-                                       activate_remote = 1;
+                                       remote_enabled = 1;
                                }
                        }
                }
@@ -837,10 +520,6 @@ main(int argc, const char *argv[])
                                }
                        }
                }
-               else if (streq(argv[i], "-D"))
-               {
-                       daemonize = 1;
-               }
                else if (streq(argv[i], "-m"))
                {
                        if ((i + 1) < argc) global.mark_time = 60 * atoll(argv[++i]);
@@ -849,38 +528,14 @@ main(int argc, const char *argv[])
                {
                        if ((i + 1) < argc) global.utmp_ttl = atol(argv[++i]);
                }
-               else if (streq(argv[i], "-fs_ttl"))
-               {
-                       if ((i + 1) < argc) global.fs_ttl = atol(argv[++i]);
-               }
                else if (streq(argv[i], "-mps_limit"))
                {
                        if ((i + 1) < argc) global.mps_limit = atol(argv[++i]);
                }
-               else if (streq(argv[i], "-l"))
-               {
-                       if ((i + 1) < argc) mp = argv[++i];
-               }
-               else if (streq(argv[i], "-c"))
-               {
-                       if ((i + 1) < argc)
-                       {
-                               i++;
-                               if ((argv[i][0] >= '0') && (argv[i][0] <= '7') && (argv[i][1] == '\0')) global.asl_log_filter = ASL_FILTER_MASK_UPTO(atoi(argv[i]));
-                       }
-               }
                else if (streq(argv[i], "-dup_delay"))
                {
                        if ((i + 1) < argc) global.bsd_max_dup_time = atoll(argv[++i]);
                }
-               else if (streq(argv[i], "-asl_in"))
-               {
-                       if ((i + 1) < argc) activate_asl_in = atoi(argv[++i]);
-               }
-               else if (streq(argv[i], "-asl_action"))
-               {
-                       if ((i + 1) < argc) activate_asl_action = atoi(argv[++i]);
-               }
                else if (streq(argv[i], "-klog_in"))
                {
                        if ((i + 1) < argc) activate_klog_in = atoi(argv[++i]);
@@ -889,17 +544,17 @@ main(int argc, const char *argv[])
                {
                        if ((i + 1) < argc) activate_bsd_in = atoi(argv[++i]);
                }
+               else if (streq(argv[i], "-udp_in"))
+               {
+                       if ((i + 1) < argc) activate_udp_in = atoi(argv[++i]);
+               }
                else if (streq(argv[i], "-bsd_out"))
                {
                        if ((i + 1) < argc) activate_bsd_out = atoi(argv[++i]);
                }
                else if (streq(argv[i], "-remote"))
                {
-                       if ((i + 1) < argc) activate_remote = atoi(argv[++i]);
-               }
-               else if (streq(argv[i], "-udp_in"))
-               {
-                       if ((i + 1) < argc) activate_udp_in = atoi(argv[++i]);
+                       if ((i + 1) < argc) remote_enabled = atoi(argv[++i]);
                }
        }
 
@@ -907,126 +562,81 @@ main(int argc, const char *argv[])
        {
                global.dbtype = DB_TYPE_FILE;
                global.db_file_max = 25600000;
-               global.asl_store_ping_time = 150;
        }
 
-       TAILQ_INIT(&Moduleq);
-       static_modules();
-       load_modules(mp);
-       aslevent_init();
-
-       if (global.debug == 0)
-       {
-               if (daemonize != 0)
-               {
-                       if (fork() != 0) exit(0);
-
-                       detach();
-                       closeall();
-               }
+       signal(SIGHUP, SIG_IGN);
 
-               writepid(&first_syslogs_start);
-       }
+       writepid(&first_syslogd_start);
 
-       init_config();
+       /*
+        * Log UTMPX boot time record
+        */
+       write_boot_log(first_syslogd_start);
 
-       signal(SIGHUP, catch_sighup);
-       signal(SIGINFO, catch_siginfo);
+       asldebug("reading launch plist\n");
+       launch_config();
 
-       /* register for network change notifications if the udp_in module is active */
-       network_change_token = -1;
-       if (activate_udp_in != 0) notify_register_signal(NETWORK_CHANGE_NOTIFICATION, SIGINFO, &network_change_token);
+       asldebug("initializing modules\n");
+       init_modules();
+       dispatch_resume(global.work_queue);
 
-       for (mod = Moduleq.tqh_first; mod != NULL; mod = mod->entries.tqe_next)
-       {
-               fd = mod->init();
-               if (fd < 0) continue;
-       }
+       /* network change notification resets UDP and BSD modules */
+    notify_register_dispatch(kNotifySCNetworkChange, &network_change_token, global.work_queue, ^(int x){
+        if (activate_udp_in != 0) udp_in_reset();
+        if (activate_bsd_out != 0) bsd_out_reset();
+    });
 
-       /*
-        * Start database server thread
-        */
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-       pthread_create(&t, &attr, (void *(*)(void *))database_server, NULL);
-       pthread_attr_destroy(&attr);
+       /* SIGHUP resets all modules */
+       global.sig_hup_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t)SIGHUP, 0, dispatch_get_main_queue());
+       dispatch_source_set_event_handler(global.sig_hup_src, ^{
+               dispatch_async(global.work_queue, ^{
+                       int i;
 
-       /*
-        * Start output worker thread
-        */
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-       pthread_create(&t, &attr, (void *(*)(void *))output_worker, NULL);
-       pthread_attr_destroy(&attr);
+                       asldebug("SIGHUP reset\n");
+                       for (i = 0; i < global.module_count; i++)
+                       {
+                               if (global.module[i]->enabled != 0) global.module[i]->reset();
+                       }
+               });
+       });
 
-       FD_ZERO(&rd);
-       FD_ZERO(&wr);
-       FD_ZERO(&ex);
+       dispatch_resume(global.sig_hup_src);
 
-       /*
-        * Log UTMPX boot time record
-        */
-       write_boot_log(first_syslogs_start);
+       /* register for DB notification (posted by dbserver) for performance */
+       notify_register_plain(kNotifyASLDBUpdate, &asl_db_token);
 
-       /*
-        * drain /dev/klog first
-        */
-       if (global.kfd >= 0)
+       /* timer for MARK facility */
+    if (global.mark_time > 0)
        {
-               FD_ZERO(&kern);
-               FD_SET(global.kfd, &kern);
-               max = global.kfd + 1;
-               while (select(max, &kern, NULL, NULL, &zto) > 0)
-               {
-                       aslevent_handleevent(&kern, &wr, &ex);
-               }
+               global.mark_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
+               dispatch_source_set_event_handler(global.mark_timer, ^{ 
+                       asl_mark();
+               });
+               dispatch_source_set_timer(global.mark_timer, dispatch_walltime(NULL, global.mark_time * NSEC_PER_SEC), global.mark_time * NSEC_PER_SEC, 0);
+               dispatch_resume(global.mark_timer);
        }
 
        /*
-        * Start launchd drain thread
+        * Start launchd service
+        * This pins a thread in _vprocmgr_log_drain.  Eventually we will either
+        * remove the whole stderr/stdout -> ASL mechanism entirely, or come up 
+        * with a communication channel that we can trigger with a dispatch source.
         */
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-       pthread_create(&t, &attr, (void *(*)(void *))launchd_drain, NULL);
-       pthread_attr_destroy(&attr);
-
-       runloop_timer = NULL;
-       timed_events(&runloop_timer);
-
-       forever
-       {
-               /* aslevent_fdsets clears the fdsets, then sets any non-zero fds from the aslevent list */
-               max = aslevent_fdsets(&rd, &wr, &ex) + 1;
+       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+               forever _vprocmgr_log_drain(NULL, NULL, launchd_callback);
+       });
 
-               status = select(max, &rd, &wr, &ex, runloop_timer);
-               if ((status < 0) && (errno == EBADF))
-               {
-                       /* Catastrophic error! */
-                       aslevent_check();
-                       abort();
-               }
-
-               if ((global.kfd >= 0) && FD_ISSET(global.kfd, &rd))
-               {
-                       /*  drain /dev/klog */
-                       FD_ZERO(&kern);
-                       FD_SET(global.kfd, &kern);
-                       max = global.kfd + 1;
-
-                       while (select(max, &kern, NULL, NULL, &zto) > 0)
-                       {
-                               aslevent_handleevent(&kern, &wr, &ex);
-                       }
-               }
+       /*
+        * Start mach server
+        * Parks a thread in database_server.  In notifyd, we found that the overhead of
+        * a dispatch source for mach calls was too high, especially on iOS.
+        */
+       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+               database_server();
+       });
 
-               if (status > 0) aslevent_handleevent(&rd, &wr, &ex);
+       dispatch_main();
 
-               if ((global.reset != RESET_NONE) || (status < 0))
-               {
-                       send_reset();
-                       global.reset = RESET_NONE;
-               }
-
-               timed_events(&runloop_timer);
-       }
+       /* NOTREACHED */
+       return 0;
 }
index 4fd10e219d31c33caa26700811cfe5d0df0ae142..dba721fce0f6feb61cfd6706585ae77398e54edb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #define MAXSOCK 16
 static int nsock = 0;
 static int ufd[MAXSOCK];
+static dispatch_source_t ufd_src[MAXSOCK];
 
 static char uline[MAXLINE + 1];
 
+static dispatch_source_t in_src[MAXSOCK];
+static dispatch_queue_t in_queue;
+
 #define FMT_LEGACY 0
 #define FMT_ASL 1
 
-aslmsg 
+void 
 udp_in_acceptmsg(int fd)
 {
        socklen_t fromlen;
@@ -61,12 +65,13 @@ udp_in_acceptmsg(int fd)
        char fromstr[64], *r, *p;
        struct sockaddr_in *s4;
        struct sockaddr_in6 *s6;
+       aslmsg m;
 
        fromlen = sizeof(struct sockaddr_storage);
        memset(&from, 0, fromlen);
 
        len = recvfrom(fd, uline, MAXLINE, 0, (struct sockaddr *)&from, &fromlen);
-       if (len <= 0) return NULL;
+       if (len <= 0) return;
 
        fromstr[0] = '\0';
        r = NULL;
@@ -76,14 +81,14 @@ udp_in_acceptmsg(int fd)
                s4 = (struct sockaddr_in *)&from;
                inet_ntop(from.ss_family, &(s4->sin_addr), fromstr, 64);
                r = fromstr;
-               asldebug("%s: recvfrom %s len %d\n", MY_ID, fromstr, len);
+               asldebug("%s: fd %d recvfrom %s len %d\n", MY_ID, fd, fromstr, len);
        }
        else if (from.ss_family == AF_INET6)
        {
                s6 = (struct sockaddr_in6 *)&from;
                inet_ntop(from.ss_family, &(s6->sin6_addr), fromstr, 64);
                r = fromstr;
-               asldebug("%s: recvfrom %s len %d\n", MY_ID, fromstr, len);
+               asldebug("%s: fd %d recvfrom %s len %d\n", MY_ID, fd, fromstr, len);
        }
 
        uline[len] = '\0';
@@ -91,17 +96,24 @@ udp_in_acceptmsg(int fd)
        p = strrchr(uline, '\n');
        if (p != NULL) *p = '\0';
 
-       return asl_input_parse(uline, len, r, SOURCE_UDP_SOCKET);
+       m = asl_input_parse(uline, len, r, SOURCE_UDP_SOCKET);
+       dispatch_async(global.work_queue, ^{ process_message(m, SOURCE_UDP_SOCKET); });
 }
 
 int
-udp_in_init(void)
+udp_in_init()
 {
-       int i, rbufsize, len;
+       int i, rbufsize, len, fd;
        launch_data_t sockets_dict, fd_array, fd_dict;
+       static dispatch_once_t once;
+
+       dispatch_once(&once, ^{
+               in_queue = dispatch_queue_create(MY_ID, NULL);
+       });
 
        asldebug("%s: init\n", MY_ID);
        if (nsock > 0) return 0;
+
        if (global.launch_dict == NULL)
        {
                asldebug("%s: launchd dict is NULL\n", MY_ID);
@@ -131,6 +143,8 @@ udp_in_init(void)
 
        for (i = 0; i < nsock; i++)
        {
+               ufd[i] = -1;
+
                fd_dict = launch_data_array_get_index(fd_array, i);
                if (fd_dict == NULL)
                {
@@ -138,49 +152,53 @@ udp_in_init(void)
                        return -1;
                }
 
-               ufd[i] = launch_data_get_fd(fd_dict);
+               fd = launch_data_get_fd(fd_dict);
 
                rbufsize = 128 * 1024;
                len = sizeof(rbufsize);
 
-               if (setsockopt(ufd[i], SOL_SOCKET, SO_RCVBUF, &rbufsize, len) < 0)
+               if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rbufsize, len) < 0)
                {
-                       asldebug("%s: couldn't set receive buffer size for socket %d: %s\n", MY_ID, ufd[i], strerror(errno));
-                       close(ufd[i]);
-                       ufd[i] = -1;
-                       continue;
+                       asldebug("%s: couldn't set receive buffer size for file descriptor %d: %s\n", MY_ID, fd, strerror(errno));
                }
 
-               if (fcntl(ufd[i], F_SETFL, O_NONBLOCK) < 0)
+               if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                {
-                       asldebug("%s: couldn't set O_NONBLOCK for socket %d: %s\n", MY_ID, ufd[i], strerror(errno));
-                       close(ufd[i]);
-                       ufd[i] = -1;
-                       continue;
+                       asldebug("%s: couldn't set O_NONBLOCK for file descriptor %d: %s\n", MY_ID, fd, strerror(errno));
                }
-       }
 
-       for (i = 0; i < nsock; i++) if (ufd[i] != -1) aslevent_addfd(SOURCE_UDP_SOCKET, ufd[i], 0, udp_in_acceptmsg, NULL, NULL);
+               ufd[i] = fd;
+
+               in_src[i] = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)fd, 0, in_queue);
+               dispatch_source_set_event_handler(in_src[i], ^{ udp_in_acceptmsg(fd); });
+
+               dispatch_resume(in_src[i]);
+       }
 
        return 0;
 }
 
+/* N.B. Does NOT close fds.  They "belong" to launchd. */
 int
 udp_in_close(void)
 {
        int i;
 
-       if (nsock == 0) return 1;
+       if (nsock == 0) return -1;
 
        for (i = 0; i < nsock; i++)
        {
-               if (ufd[i] != -1)
+               if (ufd_src[i] != NULL)
                {
-                       aslevent_removefd(ufd[i]);
-                       close(ufd[i]);
+                       dispatch_source_cancel(in_src[i]);
+                       dispatch_release(in_src[i]);
+                       in_src[i] = NULL;
                }
 
-               ufd[i] = -1;
+               if (ufd[i] != -1)
+               {
+                       ufd[i] = -1;
+               }
        }
 
        nsock = 0;
@@ -191,5 +209,6 @@ udp_in_close(void)
 int
 udp_in_reset(void)
 {
-       return 0;
+       if (udp_in_close() != 0) return -1;
+       return udp_in_init();
 }
index 88868001420a36e322cab33d6694bd60a3712822..b858dd2db51c47a62126189fc01798f5fd551f2b 100644 (file)
@@ -1,4 +1,4 @@
-.\"Copyright (c) 2004-2008 Apple Inc. All rights reserved.
+.\"Copyright (c) 2004-2011 Apple Inc. All rights reserved.
 .\"
 .\"@APPLE_LICENSE_HEADER_START@
 .\"
@@ -63,6 +63,9 @@ key val
 .D1 ""
 .Nm
 .Fl c Ar process Op filter
+.D1 ""
+.Nm 
+.Fl config Op options
 .Sh DESCRIPTION
 .Nm
 is a command-line utility for a variety of tasks relating to the Apple System Log (ASL) facility.
@@ -165,7 +168,7 @@ Another module saves messages in a data store (/var/log/asl).
 .Pp
 If invoked with no arguments,
 .Nm
-fetchs all messages from the active data store.
+fetches all messages from the active data store.
 Messages are then printed to standard output,
 subject to formatting options and character encoding as described below.
 Some log messages are read-access controlled,
@@ -331,39 +334,105 @@ A custom format should in most cases be enclosed in single quotes to prevent the
 special characters and breaking at white space.
 .Pp
 Custom format strings may include variables of the form
-.Dq $Name
-(or
-.Dq $(Name)
-if the variable is not delimited by whitespace)
-which will be expanded to the associated with the named key.
+.Dq $Name ,
+.Dq $(Name) ,
+or
+.Dq $((Name)(format)) .
+which will be expanded to the value associated with the named key.
 For example, the command:
 .Pp
-.Dl syslog -F '$Time $Host $(Sender)[$(PID)]: $Message'
+.Dl syslog -F '$Time $Host $(Sender)[$(PID)] <$((Level)(str))>: $Message'
 .Pp
 produces output similar to the 
-.Dq bsd
+.Dq std
 format.
+The simple
+.Dq $Name
+form is sufficient in most cases.
+However, the second form:
+.Dq $(Name)
+must be used if the name is not delimited by white space.
+The third form allows different formats of the value to be printed.
+For example, a message priority level may appear as an integer value (e.g.
+.Dq 3 )
+or as a string (``Error'').
+The following print formats are known.
+.Pp
+.Bl -tag -width "$((Time)([+|-]HH[:MM]))"
+.It $((Level)(str))
+Formats a Level value as a string, for example 
+.Dq Error ,
+.Dq Alert ,
+.Dq Warning ,
+and so on.
+Note that $(Level) or $Level formats the value as an integer 0 through 7.
+.It $((Time)(sec))
+Formats a Time value as the number of seconds since the Epoch.
+.It $((Time)(raw))
+Alias for $((Time)(sec)).
+.It $((Time)(local))
+Formats a Time value as a string of the form
+.Dq "Mmm dd hh:mm:ss" ,
+where Mmm is the abbreviation for the month, dd is the date (1 - 31) and hh:mm:ss is the time.
+The local timezone is used.
+.It $((Time)(lcl))
+Alias for $((Time)(local)).
+.It $((Time)(utc))
+Formats a Time value as a string of the form
+.Dq "yyyy-mm-dd hh:mm:ssZ" ,
+using Coordinated Universal Time, or the
+.Dq Zulu
+time zone.
+.It $((Time)(zulu))
+Alias for $((Time)(utc)).
+.It $((Time)(X))
+Where X may be any letter in the range A - Z or a - z.
+Formats the Time using the format
+.Dq "yyyy-mm-dd hh:mm:ssX" ,
+using the specified nautical timezone.
+Z is the same as UTC/Zulu time.  Timezones A - M (except J) decrease by one hour to the east of the
+Zulu time zone.
+Timezones N - Y increase by one hour to the west of Z.
+M and Y have the same clock time, but differ by one day.
+J is used to indicate the local timezone.
+When printing using $((Time)(J)), the output format is
+.Dq "yyyy-mm-dd hh:mm:ss" ,
+without a trailing timezone letter.
+.It $((Time)([+|-]HH[:MM]))
+Specifies an offset (+ or -) of the indicated number of hours (HH) and optionally minutes (MM) to UTC.
+The value is formatted as a string of the form
+.Dq "yyyy-mm-dd hh:mm:ss[+|-]HH:MM" .
+.El
 .Pp
-Timestamps may be printed in three formats.
-Times are generally converted to local time, except when the
-.Fl F Ar sec
+If a custom format is not being used to specify the format for Time values, then Time values
+are generally converted to local time, except when the
+.Fl F Ar raw
 option is used, in which case times are printed as the number of seconds since the epoch.
 The
 .Fl T Ar format
-option may be used to explicity control the format used for timestamps.
+option may be used to control the format used for timestamps.
 The value of
 .Ar format 
 may be one of the following:
 .Pp
-.Bl -tag -width "local"
-.It sec
+.Bl -tag -width "local or lcl"
+.It sec or raw
 Times are printed as the number of seconds since the epoch.
-.It local
+.It local or lcl
 Times are converted to the local time zone, and printed with the format
-.Dl MMM DD HH:MM:SS
-.It utc
+.Dl mmm dd hh:mm:ss
+where mmm is the month name abbreviated as three characters.
+.It utc or zulu
 Times are converted to UTC, and printed with the format
-.Dl YYYY.MM.DD HH:MM:SS UTC
+.Dl yyyy-mm-dd hh:mm:ssZ
+.It A-Z
+Times are converted to the indicated nautical time zone,
+printed in the same format as UTC.
+.Dq J
+is interpreted as the local timezone and printed in the same format,
+but without a trailing timezone letter.
+.It [+|-]hh[:mm]
+The specified offset is used to adjust time.
 .El
 .Pp
 The 
@@ -374,7 +443,7 @@ option is a short form for
 By default, control characters and non-printable characters are encoded in the output stream.
 In some cases this may make messages less natural in appearance.
 The encoding is designed to preserve all the information in the log message,
-and to prevent malicious users from spoofing or obsucring information in log messages.
+and to prevent malicious users from spoofing or obscuring information in log messages.
 .Pp
 Text in the
 .Dq std ,
@@ -399,13 +468,13 @@ Values that contain legal UTF8 are printed as strings.
 Ampersand, less than, greater than, quotation mark, and apostrophe characters are encoded according to XML conventions.
 Embedded control characters are encoded as
 .Dq &#xNN;
-where NN is the character's hexidecimal value.
+where NN is the character's hexadecimal value.
 .Pp
 Values that do not contain legal UTF8 are encoded in base-64 and printed as data objects.
 .Pp
 The 
 .Fl E Ar format
-option may be used to explicity control the text encoding.
+option may be used to explicitly control the text encoding.
 The value of
 .Ar format 
 may be one of the following:
@@ -630,40 +699,43 @@ To set a per-process filter mask, an second argument may be supplied following
 as described above for the master filter mask.
 Root access is required to set the per-process filter mask for system (UID 0) processes.
 .Pp
-The filtering described above takes place in the client library to determine which messages are sent to the
+The 
 .Nm syslogd
-daemon.
-The daemon also contains filters which determines which messages are saved in the data store.
-This determines which messages are seen when reading messages using the
-.Nm
-utility, or when viewing data store messages in the Console utility application.
+server follows filtering rules specified in the /etc/asl.conf file.
+When the remote-control mechanism is used to change the filter of a process,
+.Nm syslogd
+will save any messages received from that process until the remote-control filter is turned off.
+.Ss SERVER CONFIGURATION
+When
+.Nm syslogd
+starts up, and when it receives a HUP signal, it re-reads its configuration settings from /etc/asl.conf.
+It is sometimes useful to change configuration parameters temporarily, without needing to make changes
+to the configuration file.
+Any of the configuration options that may be set in the file (following an ``='' character) may also
+be sent to syslogd using the
+.Fl config
+flag (without an ``='' character).
+For example, to temporarily disable the message-per-second limit:
 .Pp
-The default data store filter mask permits all messages with priority levels from Emergency to Debug (level 0 to 7).
-The level may be inspected using:
+.Dl syslog -config mps_limit 0
 .Pp
-.Dl syslog -c syslogd 
+Note that only the superuser (root) may change configuration parameters.
 .Pp
-To set the data store filter mask, an second argument may be supplied following
-.Fl c Li syslog
-as described above.
-For example, to save messages with priority level Error or less in the data store:
+In addition to the parameter setting options that are described in the
+.Xr asl.conf 5
+manual page, an additional option:
 .Pp
-.Dl syslog -c syslog -e
+.Dl syslog -config reset
 .Pp
-The 
-.Nm syslogd
-server also follows filtering rules specified in the /etc/asl.conf file.
-When the remote-control mechanism is used to change the filter of a process,
+will cause
 .Nm syslogd
-will save any messages received from that process until the remote-control filter is turned off.
-It is no longer necessary to adjust the filtering for both a process and for
-.Nm syslogd 
-to have messages saved in the ASL data store.
+to reset its configuration.
 .Sh SEE ALSO
 .Xr syslogd 8 ,
 .Xr logger 1 ,
 .Xr asl 3 ,
 .Xr syslog 3 ,
+.Xr asl.conf 5 .
 .Sh HISTORY
 The
 .Nm
index 11d2613fc7d80f99f4e8db3aea3fa3c44dfd5985..d72bb55db0d582195395e510a7f06a3de3deeff1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -69,6 +69,9 @@
 /* Shared with Libc */
 #define NOTIFY_RC "com.apple.asl.remote"
 
+/* XXX add to asl_private.h */
+#define ASL_OPT_CONTROL "control"
+
 #define SEARCH_EOF -1
 #define SEARCH_NULL 0
 #define SEARCH_MATCH 1
@@ -77,7 +80,6 @@
 #define PROC_NOT_UNIQUE -2
 
 #define RC_MASTER -1
-#define RC_SYSLOGD -2
 
 #define CHUNK 64
 #define forever for(;;)
 #define SEND_FORMAT_LEGACY 0
 #define SEND_FORMAT_ASL 1
 
-#define TIME_SEC               0x00000010
-#define TIME_UTC               0x00000020
-#define TIME_LCL               0x00000040
-
 #define FORMAT_RAW             0x00000100
 #define FORMAT_LEGACY  0x00000200
 #define FORMAT_STD             0x00000400
@@ -131,6 +129,7 @@ static const char *sort_key_2 = NULL;
 static int sort_numeric = 0;
 static char *last_printmsg_str = NULL;
 static int last_printmsg_count = 0;
+static const char *tfmt = NULL;
 
 #ifdef CONFIG_IPHONE
 static uint32_t dbselect = DB_SELECT_SYSLOGD;
@@ -176,6 +175,9 @@ usage()
        fprintf(stderr, "   d = Debug\n");
        fprintf(stderr, "   a minus sign preceeding a single letter means \"up to\" that level\n");
        fprintf(stderr, "\n");
+       fprintf(stderr, "%s -config params...\n", myname);
+       fprintf(stderr, "   set or reset syslogd configuration parameters\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");
@@ -512,7 +514,6 @@ rcontrol_name(pid_t pid, uid_t uid)
 {
        static char str[1024];
 
-       if (pid == RC_SYSLOGD) return NOTIFY_SYSTEM_ASL_FILTER;
        if (pid == RC_MASTER) return NOTIFY_SYSTEM_MASTER;
 
        memset(str, 0, sizeof(str));
@@ -525,23 +526,19 @@ int
 rcontrol_get(pid_t pid, uid_t uid)
 {
        int filter, status;
-       const char *name;
 
        filter = 0;
 
        if (pid < 0)
        {
-               name = "Master";
-               if (pid == RC_SYSLOGD) name = "ASL Data Store";
-
                status = rcontrol_get_string(rcontrol_name(pid, uid), &filter);
                if (status == NOTIFY_STATUS_OK)
                {
-                       printf("%s filter mask: %s\n", name, asl_filter_string(filter));
+                       printf("Master filter mask: %s\n", asl_filter_string(filter));
                        return 0;
                }
 
-               printf("Unable to determine %s filter mask\n", name);
+               printf("Unable to determine master filter mask\n");
                return -1;
        }
 
@@ -560,14 +557,12 @@ int
 rcontrol_set(pid_t pid, uid_t uid, int filter)
 {
        int status;
-       const char *name, *rcname;
+       const char *rcname;
 
        rcname = rcontrol_name(pid, uid);
 
        if (pid < 0)
        {
-               name = "Master";
-               if (pid == RC_SYSLOGD) name = "ASL Data Store";
                status = rcontrol_set_string(rcname, filter);
 
                if (status == NOTIFY_STATUS_OK)
@@ -576,7 +571,7 @@ rcontrol_set(pid_t pid, uid_t uid, int filter)
                        return 0;
                }
 
-               printf("Unable to set %s syslog filter mask: %s\n", name, notify_status_string(status));
+               printf("Unable to set master syslog filter mask: %s\n", notify_status_string(status));
                return -1;
        }
 
@@ -777,9 +772,8 @@ syslog_remote_control(int argc, char *argv[])
 
        if ((!strcmp(argv[2], "syslogd")) || (!strcmp(argv[2], "syslog")))
        {
-               pid = RC_SYSLOGD;
-               uid = 0;
-               status = 0;
+               fprintf(stderr, "%s: does not have a filter mask\n", argv[2]);
+               return -1;
        }
        else if (_isanumber(argv[2]) != 0)
        {
@@ -809,7 +803,6 @@ syslog_remote_control(int argc, char *argv[])
        if (argc == 4)
        {
                if ((pid == RC_MASTER) && (!strcasecmp(argv[3], "off"))) mask = 0;
-               else if ((pid == RC_SYSLOGD) && (!strcasecmp(argv[3], "off"))) mask = 0;
                else
                {
                        mask = asl_string_to_filter(argv[3]);
@@ -833,7 +826,7 @@ syslog_remote_control(int argc, char *argv[])
 int
 syslog_send(int argc, char *argv[])
 {
-       int i, start, kv, len, rfmt, rlevel, filter, status;
+       int i, start, kv, len, rfmt, rlevel;
        aslclient asl;
        aslmsg m;
        char tmp[64], *str, *rhost;
@@ -906,18 +899,6 @@ syslog_send(int argc, char *argv[])
 
        if (rhost == NULL)
        {
-               filter = 0;
-               status = rcontrol_get_string(rcontrol_name(RC_SYSLOGD, 0), &filter);
-               if (status != 0)
-               {
-                       fprintf(stderr, "Warning: Can't get current syslogd ASL filter value\n");
-               }
-               else if ((ASL_FILTER_MASK(rlevel) & filter) == 0)
-               {
-                       fprintf(stderr, "Warning: The current syslogd ASL filter value (%s)\n", asl_filter_string(filter));
-                       fprintf(stderr, "         will exclude this message from the ASL database\n");
-               }
-
                asl_send(asl, m);
        }
        else if (rfmt == SEND_FORMAT_ASL)
@@ -938,6 +919,48 @@ syslog_send(int argc, char *argv[])
        return 0;
 }
 
+int
+syslog_config(int argc, char *argv[])
+{
+       int i;
+       uid_t uid;
+       aslclient asl;
+       aslmsg m;
+       asl_string_t *str;
+
+       uid = geteuid();
+       if (uid != 0)
+       {
+               fprintf(stderr, "syslogd parameters may only be set by the superuser\n");
+               return -1;
+       }
+
+       str = asl_string_new(0);
+       asl_string_append(str, "= ");
+
+       for (i = 2; i < argc; i++)
+       {
+               asl_string_append(str, argv[i]);
+               if ((i + 1) < argc) asl_string_append(str, " ");
+       }
+
+       asl = asl_open(myname, "syslog", 0);
+
+       m = asl_new(ASL_TYPE_MSG);
+       asl_set(m, ASL_KEY_LEVEL, ASL_STRING_NOTICE);
+       asl_set(m, ASL_KEY_OPTION, ASL_OPT_CONTROL);
+       asl_set(m, ASL_KEY_SENDER, myname);
+       asl_set(m, ASL_KEY_MSG, asl_string_bytes(str));
+
+       asl_send(asl, m);
+
+       asl_string_free(str);
+       asl_free(m);
+       asl_close(asl);
+
+       return 0;
+}
+
 static void
 print_xml_header(FILE *f)
 {
@@ -962,7 +985,7 @@ static void
 printmsg(FILE *f, aslmsg msg, char *fmt, int pflags)
 {
        char *str;
-       const char *mf, *tf;
+       const char *mf;
        uint32_t encode, len, status;
        uint64_t xid;
 
@@ -991,12 +1014,8 @@ printmsg(FILE *f, aslmsg msg, char *fmt, int pflags)
        else if (pflags & FORMAT_LEGACY) mf = ASL_MSG_FMT_BSD;
        else if (pflags & FORMAT_XML) mf = ASL_MSG_FMT_XML;
 
-       tf = ASL_TIME_FMT_SEC;
-       if (pflags & TIME_UTC) tf = ASL_TIME_FMT_UTC;
-       if (pflags & TIME_LCL) tf = ASL_TIME_FMT_LCL;
-
        len = 0;
-       str = asl_format_message((asl_msg_t *)msg, mf, tf, encode, &len);
+       str = asl_format_message((asl_msg_t *)msg, mf, tfmt, encode, &len);
        if (str == NULL) return;
 
        if (pflags & COMPRESS_DUPS)
@@ -1158,11 +1177,13 @@ filter_and_print(aslmsg msg, asl_search_result_t *ql, FILE *f, char *pfmt, int p
        if (did_match != 0) printmsg(f, msg, pfmt, pflags);
 }
 
+#ifdef CONFIG_IPHONE
 void
 syslogd_direct_watch(FILE *f, char *pfmt, int pflags, asl_search_result_t *ql)
 {
        struct sockaddr_in address;
-       int i, bytes, n, inlen, sock, stream, status;
+       int i, bytes, sock, stream, status;
+       uint32_t n, inlen;
        uint16_t port;
        socklen_t addresslength;
        char *str, buf[DIRECT_BUF_SIZE];
@@ -1178,13 +1199,12 @@ syslogd_direct_watch(FILE *f, char *pfmt, int pflags, asl_search_result_t *ql)
                }
        }
 
-reset:
-
        addresslength = sizeof(address);
        sock = socket(AF_INET, SOCK_STREAM, 0);
        port = (arc4random() % (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)) + IPPORT_HIFIRSTAUTO;
 
-       address.sin_addr.s_addr = 0;
+       memset(&address, 0, addresslength);
+       address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
        address.sin_family = AF_INET;
        address.sin_port = htons(port);
 
@@ -1225,18 +1245,16 @@ reset:
        forever
        {
                inlen = 0;
+               errno = 0;
                bytes = recvfrom(stream, &n, sizeof(n), 0, NULL, NULL);
-               if (bytes == 0) break;
+               if (bytes <= 0)
+               {
+                       fprintf(stderr, "\nrecvfrom (message length) returned %d (errno %d) - exiting\n", bytes, errno);
+                       break;
+               }
                else inlen = ntohl(n);
 
                if (inlen == 0) continue;
-               if (inlen > MAX_DIRECT_SIZE)
-               {
-                       fprintf(f, "\n*** received invalid message data [%d] from syslogd - resetting connection ***\n\n", inlen);
-                       close(stream);
-                       close(sock);
-                       goto reset;
-               }
 
                str = NULL;
                if (inlen <= DIRECT_BUF_SIZE)
@@ -1258,11 +1276,24 @@ reset:
                n = 0;
                while (n < inlen)
                {
+                       errno = 0;
                        bytes = recvfrom(stream, str + n, inlen - n, 0, NULL, NULL);
-                       if (bytes == 0) break;
+                       if (bytes <= 0)
+                       {
+                               fprintf(stderr, "\nrecvfrom (message body) returned %d (errno %d) at length %d of %d - exiting\n", bytes, errno, n, inlen);
+                               break;
+                       }
                        else n += bytes;
                }
 
+               if (n < inlen)
+               {
+                       fprintf(stderr, "\ntruncated message: expected %d bytes received %d bytes\n", inlen, n);
+                       close(stream);
+                       close(sock);
+                       exit(1);
+               }
+
                msg = (aslmsg)asl_msg_from_string(str);
                if (str != buf) free(str);
                filter_and_print(msg, ql, f, pfmt, pflags);
@@ -1274,6 +1305,7 @@ reset:
 
        address.sin_addr.s_addr = 0;
 }
+#endif
 
 int
 sort_compare_key(const void *a, const void *b, const char *key)
@@ -1656,7 +1688,7 @@ int
 main(int argc, char *argv[])
 {
        FILE *outfile;
-       int i, j, n, watch, status, pflags, tflags, iamroot, user_tflag, export_preserve_id, saw_dash_d, since_boot;
+       int i, j, n, watch, status, pflags, iamroot, user_tflag, export_preserve_id, saw_dash_d, since_boot;
        int notify_file, notify_token;
        asl_search_result_t *qlist;
        asl_msg_t *cq;
@@ -1673,7 +1705,6 @@ main(int argc, char *argv[])
        tail_count = 0;
        batch = FETCH_BATCH;
        pflags = FORMAT_STD | COMPRESS_DUPS;
-       tflags = TIME_LCL;
        encode = ASL_ENCODE_SAFE;
        cq = NULL;
        exportname = NULL;
@@ -1694,13 +1725,19 @@ main(int argc, char *argv[])
                        exit(0);
                }
 
-               if (!strcmp(argv[i], "-time"))
+               if ((!strcmp(argv[i], "-time")) || (!strcmp(argv[i], "--time")))
                {
                        qmin = time(NULL);
                        printf("%llu\n", qmin);
                        exit(0);
                }
 
+               if ((!strcmp(argv[i], "-config")) || (!strcmp(argv[i], "--config")))
+               {
+                       syslog_config(argc, argv);
+                       exit(0);
+               }
+
                if (!strcmp(argv[i], "-s"))
                {
                        syslog_send(argc, argv);
@@ -1850,7 +1887,7 @@ main(int argc, char *argv[])
                }
                else if (!strcmp(argv[i], "-u"))
                {
-                       tflags = TIME_UTC;
+                       tfmt = "Z";
                        user_tflag = 1;
                }
                else if ((!strcmp(argv[i], "-x")) || (!strcmp(argv[i], "-X")))
@@ -1896,7 +1933,7 @@ main(int argc, char *argv[])
                        if (!strcmp(argv[i], "raw"))
                        {
                                pflags = FORMAT_RAW;
-                               if (user_tflag == 0) tflags = TIME_SEC;
+                               if (user_tflag == 0) tfmt = "sec";
                        }
                        else if (!strcmp(argv[i], "std"))
                        {
@@ -1926,13 +1963,8 @@ main(int argc, char *argv[])
                        }
 
                        i++;
+                       tfmt = argv[i];
                        user_tflag = 1;
-
-                       if (!strcmp(argv[i], "sec")) tflags = TIME_SEC;
-                       else if (!strcmp(argv[i], "utc")) tflags = TIME_UTC;
-                       else if (!strcmp(argv[i], "local")) tflags = TIME_LCL;
-                       else if (!strcmp(argv[i], "lcl")) tflags = TIME_LCL;
-                       else  tflags = TIME_LCL;
                }
                else if (!strcmp(argv[i], "-nodc"))
                {
@@ -2039,7 +2071,6 @@ main(int argc, char *argv[])
                }
        }
 
-       pflags |= tflags;
        pflags |= encode;
 
        outfile = stdout;
@@ -2134,13 +2165,13 @@ main(int argc, char *argv[])
                asl_set_query(bq, "ut_type", "2", ASL_QUERY_OP_EQUAL);
                bt->count = 1;
                bt->msg[0] = (asl_msg_t *)bq;
-       
+
                /* XXX */
                search_once(NULL, NULL, 0, bt, -1, &qmin, 1, 1, -1, 0);
                asl_free(bq);
                free(bt->msg);
                free(bt);
-       
+
                if (qmin > 0) qmin--;
                tail_count = 0;
        }
@@ -2171,7 +2202,12 @@ main(int argc, char *argv[])
        {
                if (dbselect == DB_SELECT_SYSLOGD)
                {
+#ifdef CONFIG_IPHONE
                        syslogd_direct_watch(outfile, pfmt, pflags, qlist);
+#else
+                       fprintf(stderr, "Warning: -w flag cannot be used when querying syslogd directly\n");
+                       exit(1);
+#endif
                }
                else if (notify_token == -1)
                {