]> git.saurik.com Git - apple/syslog.git/blobdiff - syslogd.tproj/syslogd.c
syslog-356.200.4.tar.gz
[apple/syslog.git] / syslogd.tproj / syslogd.c
index 03776548ee299647e50805c0664cc6c29d3d3a15..2d45dc5839118d943a4385695ccfa8934f05b0c6 100644 (file)
 /*
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * "Portions Copyright (c) 2004 Apple Computer, Inc.  All Rights
- * Reserved.  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 1.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.apple.com/publicsource and read it before using
- * this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
  * 
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License."
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
 
+#include <TargetConditionals.h>
+
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
-#include <signal.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/mach_time.h>
+#include <servers/bootstrap.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
 #include <sys/fcntl.h>
+#include <sys/errno.h>
 #include <sys/queue.h>
 #include <sys/time.h>
+#include <sys/un.h>
+#include <pthread.h>
 #include <dirent.h>
 #include <dlfcn.h>
 #include <libgen.h>
 #include <notify.h>
+#include <notify_keys.h>
+#include <utmpx.h>
+#include <asl_private.h>
+
+#if !TARGET_OS_IPHONE
+#include <quarantine.h>
+#endif
 #include "daemon.h"
 
-#define DEFAULT_MARK_SEC 0
-#define DEFAULT_PRUNE_DAYS 7
-#define PRUNE_AFTER_START_DELAY 300
+#define SERVICE_NAME "com.apple.system.logger"
+#define SERVER_STATUS_ERROR -1
+#define SERVER_STATUS_INACTIVE 0
+#define SERVER_STATUS_ACTIVE 1
+#define SERVER_STATUS_ON_DEMAND 2
 
-#define NOTIFY_DELAY 1
+#define BILLION 1000000000
 
-#define streq(A,B) (strcmp(A,B)==0)
-#define forever for(;;)
+#define NOTIFY_DELAY 1
 
-static int debug = 0;
-static int reset = 0;
+extern int _malloc_no_asl_log;
 
-static TAILQ_HEAD(ml, module_list) Moduleq;
+#if TARGET_IPHONE_SIMULATOR
+const char *_path_pidfile;
+const char *_path_syslogd_log;
+#endif
 
 /* global */
-int asl_log_filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE);
-int prune = 0;
-
-extern int __notify_78945668_info__;
+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();
+#if !TARGET_IPHONE_SIMULATOR
+/* Input Modules */
+int klog_in_init(void);
+int klog_in_reset(void);
+int klog_in_close(void);
 static int activate_klog_in = 1;
+#endif
 
-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();
+#if !TARGET_IPHONE_SIMULATOR
+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;
+#endif
+
+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 = 0;
+#if !TARGET_IPHONE_SIMULATOR
+/* Interactive Module */
+int remote_init(void);
+int remote_reset(void);
+int remote_close(void);
+static int remote_enabled = 0;
+#endif
 
-/*
- * 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.
- */
+extern void database_server();
 
-static int
-static_modules()
+static void
+init_modules()
 {
-       struct module_list *tmp;
-
-       if (activate_asl_in != 0)
+#if !TARGET_IPHONE_SIMULATOR
+       module_t *m_klog_in, *m_bsd_out, *m_udp_in, *m_remote;
+#endif
+       module_t *m_asl, *m_bsd_in;
+       int m = 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_in");
-               tmp->module = NULL;
-               tmp->init = asl_in_init;
-               tmp->reset = asl_in_reset;
-               tmp->close = asl_in_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
+               asldebug("alloc failed (init_modules asl_action)\n");
+               exit(1);
        }
 
-       if (activate_asl_action != 0)
-       {
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL) return 1;
-               tmp->name = strdup("asl_action");
-               tmp->module = NULL;
-               tmp->init = asl_action_init;
-               tmp->reset = asl_action_reset;
-               tmp->close = asl_action_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
-       }
+       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;
 
-       if (activate_klog_in != 0)
-       {
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL) return 1;
-               tmp->name = strdup("klog_in");
-               tmp->module = NULL;
-               tmp->init = klog_in_init;
-               tmp->reset = klog_in_reset;
-               tmp->close = klog_in_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
-       }
+       if (m_asl->enabled) m_asl->init();
 
-       if (activate_bsd_in != 0)
+#if !TARGET_IPHONE_SIMULATOR
+       /* 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("bsd_in");
-               tmp->module = NULL;
-               tmp->init = bsd_in_init;
-               tmp->reset = bsd_in_reset;
-               tmp->close = bsd_in_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
+               asldebug("alloc failed (init_modules bsd_out)\n");
+               exit(1);
        }
 
-       if (activate_bsd_out != 0)
+       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 (m_bsd_out->enabled)
        {
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL) return 1;
-               tmp->name = strdup("bsd_out");
-               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_udp_in != 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("udp_in");
-               tmp->module = NULL;
-               tmp->init = udp_in_init;
-               tmp->reset = udp_in_reset;
-               tmp->close = udp_in_close;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
+               asldebug("alloc failed (init_modules klog_in)\n");
+               exit(1);
        }
 
-       return 0;
-}
-
-/*
- * 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(char *mp)
-{
-       DIR *d;
-       struct dirent *de;
-       struct module_list *tmp;
-       void *c, *bn;
-       char *modulepath = NULL;
+       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;
 
-       d = opendir(mp);
-       if (d == NULL) return -1;
+       if (m_klog_in->enabled) m_klog_in->init();
+#endif
 
-       while (NULL != (de = readdir(d)))
+       /* BSD (UNIX domain socket) input module */
+       m_bsd_in = (module_t *)calloc(1, sizeof(module_t));
+       if (m_bsd_in == NULL)
        {
-               if (de->d_name[0] == '.') continue;
-
-               /* Must have ".so" in the name" */
-               if (!strstr(de->d_name, ".so")) continue;
+               asldebug("alloc failed (init_modules bsd_in)\n");
+               exit(1);
+       }
 
-               asprintf(&modulepath, "%s/%s", mp, de->d_name);
-               if (!modulepath) continue;
+       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;
 
-               c = dlopen(modulepath, RTLD_LOCAL);
-               if (c == NULL)
-               {
-                       free(modulepath);
-                       continue;
-               }
+       if (m_bsd_in->enabled) m_bsd_in->init();
 
-               tmp = calloc(1, sizeof(struct module_list));
-               if (tmp == NULL)
-               {
-                       free(modulepath);
-                       dlclose(c);
-                       continue;
-               }
+#if !TARGET_IPHONE_SIMULATOR
+       /* network (syslog protocol) input module */
+       m_udp_in = (module_t *)calloc(1, sizeof(module_t));
+       if (m_udp_in == NULL)
+       {
+               asldebug("alloc failed (init_modules udp_in)\n");
+               exit(1);
+       }
 
-               bn = basename(modulepath);
-               tmp->name = strdup(bn);
-               tmp->module = c;
-               TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
+       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->init = dlsym(tmp->module, "aslmod_init");
-               tmp->reset = dlsym(tmp->module, "aslmod_reset");
-               tmp->close = dlsym(tmp->module, "aslmod_close");
+       if (m_udp_in->enabled) m_udp_in->init();
 
-               free(modulepath);
+       /* 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);
        }
 
-       closedir(d);
+       m_remote->name = "remote";
+       m_remote->enabled = remote_enabled;
+       m_remote->init = remote_init;
+       m_remote->reset = remote_reset;
+       m_remote->close = remote_close;
+
+       if (m_remote->enabled) m_remote->init();
+#endif /* TARGET_IPHONE_SIMULATOR */
+
+       /* save modules in global.module array */
+#if TARGET_IPHONE_SIMULATOR
+       global.module_count = 2;
+#else
+       global.module_count = 6;
+#endif
+       global.module = (module_t **)calloc(global.module_count, sizeof(module_t *));
+       if (global.module == NULL)
+       {
+               asldebug("alloc failed (init_modules)\n");
+               exit(1);
+       }
 
-       return 0;
+       global.module[m++] = m_asl;
+       global.module[m++] = m_bsd_in;
+#if !TARGET_IPHONE_SIMULATOR
+       global.module[m++] = m_bsd_out;
+       global.module[m++] = m_klog_in;
+       global.module[m++] = m_udp_in;
+       global.module[m++] = m_remote;
+#endif
 }
 
 static void
-writepid(void)
+writepid(int *first)
 {
+       struct stat sb;
        FILE *fp;
 
+       if (first != NULL)
+       {
+               *first = 1;
+               memset(&sb, 0, sizeof(struct stat));
+               if (stat(_PATH_PIDFILE, &sb) == 0)
+               {
+                       if (S_ISREG(sb.st_mode)) *first = 0;
+               }
+       }
+
        fp = fopen(_PATH_PIDFILE, "w");
        if (fp != NULL)
        {
-               fprintf(fp, "%d\n", getpid());
+               fprintf(fp, "%d\n", global.pid);
                fclose(fp);
        }
 }
 
-static void
-closeall(void)
+void
+launch_config()
 {
-       int i;
+       launch_data_t tmp, pdict;
+       kern_return_t status;
 
-       for (i = getdtablesize() - 1; i >= 0; i--) close(i);
+       tmp = launch_data_new_string(LAUNCH_KEY_CHECKIN);
+       global.launch_dict = launch_msg(tmp);
+       launch_data_free(tmp);
 
-       open("/dev/null", O_RDWR, 0);
-       dup(0);
-       dup(0);
-}
+       if (global.launch_dict == NULL)
+       {
+               asldebug("%d launchd checkin failed\n", global.pid);
+               exit(1);
+       }
 
-static void
-detach(void)
-{
-       signal(SIGINT, SIG_IGN);
-       signal(SIGPIPE, SIG_IGN);
-       setsid();
+       tmp = launch_data_dict_lookup(global.launch_dict, LAUNCH_JOBKEY_MACHSERVICES);
+       if (tmp == NULL)
+       {
+               asldebug("%d launchd lookup of LAUNCH_JOBKEY_MACHSERVICES failed\n", global.pid);
+               exit(1);
+       }
+
+       pdict = launch_data_dict_lookup(tmp, SERVICE_NAME);
+       if (pdict == NULL)
+       {
+               asldebug("%d launchd lookup of SERVICE_NAME failed\n", global.pid);
+               exit(1);
+       }
+
+       global.server_port = launch_data_get_machport(pdict);
+
+       /* 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)
+       {
+               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)
+       {
+               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)
+       {
+               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)
+       {
+               asldebug("mach_port_move_member dead_session_port failed (%u)", status);
+               exit(1);
+       }
 }
 
-static void
-catch_sighup(int x)
+void
+config_debug(int enable, const char *path)
 {
-       reset = 1;
+       OSSpinLockLock(&global.lock);
+
+       global.debug = enable;
+       free(global.debug_file);
+       global.debug_file = NULL;
+       if (path != NULL) global.debug_file = strdup(path);
+
+       OSSpinLockUnlock(&global.lock);
 }
 
-static void
-catch_sigwinch(int x)
+void
+config_data_store(int type, uint32_t file_max, uint32_t memory_max, uint32_t str_memory_max)
 {
-       prune = 1;
+       pthread_mutex_lock(global.db_lock);
+
+       if (global.dbtype & DB_TYPE_FILE)
+       {
+               asl_store_close(global.file_db);
+               global.file_db = NULL;
+       }
+
+       if (global.dbtype & DB_TYPE_MEMORY)
+       {
+               asl_memory_close(global.memory_db);
+               global.memory_db = NULL;
+       }
+
+       global.dbtype = type;
+       global.db_file_max = file_max;
+       global.db_memory_max = memory_max;
+       global.db_memory_str_max = str_memory_max;
+
+       pthread_mutex_unlock(global.db_lock);
 }
 
-static void
-send_reset(void)
+void
+write_boot_log(int first)
 {
-       struct module_list *mod;
+       int mib[2] = {CTL_KERN, KERN_BOOTTIME};
+       size_t len;
+       asl_msg_t *msg;
+       char buf[256];
+       struct utmpx utx;
+
+       if (first == 0)
+       {
+               /* syslogd restart */
+               msg = asl_msg_new(ASL_TYPE_MSG);
+               if (msg == NULL) return;
+
+               asl_msg_set_key_val(msg, ASL_KEY_SENDER, "syslogd");
+               asl_msg_set_key_val(msg, ASL_KEY_FACILITY, "daemon");
+               asl_msg_set_key_val(msg, ASL_KEY_LEVEL, "Notice");
+               asl_msg_set_key_val(msg, ASL_KEY_UID, "0");
+               asl_msg_set_key_val(msg, ASL_KEY_GID, "0");
+               snprintf(buf, sizeof(buf), "%u", global.pid);
+               asl_msg_set_key_val(msg, ASL_KEY_PID, buf);
+               asl_msg_set_key_val(msg, ASL_KEY_MSG, "--- syslogd restarted ---");
+               process_message(msg, SOURCE_INTERNAL);
+               return;
+       }
 
-       for (mod = Moduleq.tqh_first; mod != NULL; mod = mod->entries.tqe_next)
+       bzero(&utx, sizeof(utx));
+       utx.ut_type = BOOT_TIME;
+       utx.ut_pid = 1;
+
+       /* get the boot time */
+       len = sizeof(struct timeval);
+       if (sysctl(mib, 2, &utx.ut_tv, &len, NULL, 0) < 0)
        {
-               if (mod->reset != NULL) mod->reset();
+               gettimeofday(&utx.ut_tv, NULL);
        }
+
+       pututxline(&utx);
+
+       msg = asl_msg_new(ASL_TYPE_MSG);
+       if (msg == NULL) return;
+
+       asl_msg_set_key_val(msg, ASL_KEY_SENDER, "bootlog");
+       asl_msg_set_key_val(msg, ASL_KEY_FACILITY, "com.apple.system.utmpx");
+       asl_msg_set_key_val(msg, ASL_KEY_LEVEL, "Notice");
+       asl_msg_set_key_val(msg, ASL_KEY_UID, "0");
+       asl_msg_set_key_val(msg, ASL_KEY_GID, "0");
+       asl_msg_set_key_val(msg, ASL_KEY_PID, "0");
+       snprintf(buf, sizeof(buf), "BOOT_TIME %lu %u", (unsigned long)utx.ut_tv.tv_sec, (unsigned int)utx.ut_tv.tv_usec);
+       asl_msg_set_key_val(msg, ASL_KEY_MSG, buf);
+       asl_msg_set_key_val(msg, "ut_id", "0x00 0x00 0x00 0x00");
+       asl_msg_set_key_val(msg, "ut_pid", "1");
+       asl_msg_set_key_val(msg, "ut_type", "2");
+       snprintf(buf, sizeof(buf), "%lu", (unsigned long)utx.ut_tv.tv_sec);
+       asl_msg_set_key_val(msg, ASL_KEY_TIME, buf);
+       asl_msg_set_key_val(msg, "ut_tv.tv_sec", buf);
+       snprintf(buf, sizeof(buf), "%u", (unsigned int)utx.ut_tv.tv_usec);
+       asl_msg_set_key_val(msg, "ut_tv.tv_usec", buf);
+       snprintf(buf, sizeof(buf), "%u%s", (unsigned int)utx.ut_tv.tv_usec, (utx.ut_tv.tv_usec == 0) ? "" : "000");
+       asl_msg_set_key_val(msg, ASL_KEY_TIME_NSEC, buf);
+
+       process_message(msg, SOURCE_INTERNAL);
 }
 
 int
-main(int argc, char *argv[])
+main(int argc, const char *argv[])
 {
-       struct module_list *mod;
-       fd_set rd, wr, ex;
-       int fd, i, max, status, pdays, daemonize;
-       time_t lastmark, msec, ssec, tick, delta, ptime, notify_time;
-       char *mp, *str;
-       struct timeval timeout, *pto;
-       asl_msg_t *pq;
-
-       mp = _PATH_MODULE_LIB;
-       msec = DEFAULT_MARK_SEC;
-       pdays = DEFAULT_PRUNE_DAYS;
-       daemonize = 0;
-       __notify_78945668_info__ = -1;
+       int32_t i;
+       uint64_t master_val;
+#if !TARGET_IPHONE_SIMULATOR
+       int network_change_token;
+#endif
+       int quota_file_token, asl_db_token, master_token;
+       char tstr[32], *notify_key;
+       time_t now;
+       int first_syslogd_start = 1;
+
+#if TARGET_IPHONE_SIMULATOR
+       const char *sim_log_dir = getenv("SIMULATOR_LOG_ROOT");
+       const char *sim_resource_dir = getenv("SIMULATOR_SHARED_RESOURCES_DIRECTORY");
+       char *p;
+
+       /* assert is evil */
+       assert(sim_log_dir && sim_resource_dir);
+
+       asprintf((char **)&_path_syslogd_log, "%s/syslogd.log", sim_log_dir);
+       asprintf((char **)&_path_pidfile, "%s/var/run/syslog.pid", sim_resource_dir);
+
+       if (_path_syslogd_log == NULL) _path_syslogd_log = "/tmp/syslogd.log";
+       else mkpath_np(sim_log_dir, 0755);
+
+       if (_path_pidfile == NULL)
+       {
+               _path_pidfile = "/tmp/syslog.pid";
+       }
+       else
+       {
+               p = strrchr(_path_pidfile, '/');
+               *p = '\0';
+               mkpath_np(_path_pidfile, 0755);
+               *p = '/';
+       }
+#endif
+
+       /* Set I/O policy */
+       setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_PASSIVE);
+
+#if !TARGET_OS_IPHONE
+       /* Set Quarantine */
+       qtn_proc_t qp = qtn_proc_alloc();
+       qtn_proc_set_identifier(qp, "com.apple.syslogd");
+       qtn_proc_set_flags(qp, QTN_FLAG_SANDBOX | QTN_FLAG_HARD);
+       qtn_proc_apply_to_self(qp);
+       qtn_proc_free(qp);
+#endif
+
+       memset(&global, 0, sizeof(struct global_s));
+
+       global.db_lock = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t));
+       pthread_mutex_init(global.db_lock, NULL);
 
+       /*
+        * Create work queue, but suspend until output modules are initialized.
+        */
+       global.work_queue = dispatch_queue_create("Work Queue", NULL);
+       dispatch_suspend(global.work_queue);
+
+       init_globals();
+
+#if TARGET_OS_EMBEDDED
+       remote_enabled = 1;
+       activate_bsd_out = 0;
+#endif
+
+       /* prevent malloc from calling ASL on error */
+       _malloc_no_asl_log = 1;
+
+       /* first pass sets up default configurations */
        for (i = 1; i < argc; i++)
        {
-               if (streq(argv[i], "-d"))
+               if (streq(argv[i], "-config"))
                {
-                       debug = 1;
+                       if (((i + 1) < argc) && (argv[i+1][0] != '-'))
+                       {
+                               i++;
+                               if (streq(argv[i], "mac"))
+                               {
+                                       global.dbtype = DB_TYPE_FILE;
+                                       global.db_file_max = 25600000;
+                               }
+                               else if (streq(argv[i], "appletv"))
+                               {
+                                       global.dbtype = DB_TYPE_FILE;
+                                       global.db_file_max = 10240000;
+                               }
+                               else if (streq(argv[i], "iphone"))
+                               {
+#if TARGET_IPHONE_SIMULATOR
+                                       global.dbtype = DB_TYPE_FILE;
+                                       global.db_file_max = 25600000;
+#else
+                                       global.dbtype = DB_TYPE_MEMORY;
+                                       remote_enabled = 1;
+#endif
+                               }
+                       }
                }
-               if (streq(argv[i], "-D"))
+       }
+
+       for (i = 1; i < argc; i++)
+       {
+               if (streq(argv[i], "-d"))
                {
-                       daemonize = 1;
+                       global.debug = 1;
+                       if (((i+1) < argc) && (argv[i+1][0] != '-')) global.debug_file = strdup(argv[++i]);
                }
-               if (streq(argv[i], "-u"))
+               else if (streq(argv[i], "-db"))
                {
-                       activate_udp_in = 1;
+                       if (((i + 1) < argc) && (argv[i+1][0] != '-'))
+                       {
+                               i++;
+                               if (streq(argv[i], "file"))
+                               {
+                                       global.dbtype |= DB_TYPE_FILE;
+                                       if (((i + 1) < argc) && (argv[i+1][0] != '-')) global.db_file_max = atol(argv[++i]);
+                               }
+                               else if (streq(argv[i], "memory"))
+                               {
+                                       global.dbtype |= DB_TYPE_MEMORY;
+                                       if (((i + 1) < argc) && (argv[i+1][0] != '-')) global.db_memory_max = atol(argv[++i]);
+                               }
+                       }
                }
                else if (streq(argv[i], "-m"))
                {
-                       if ((i + 1) < argc) msec = 60 * atoi(argv[++i]);
+                       if ((i + 1) < argc) global.mark_time = 60 * atoll(argv[++i]);
                }
-               else if (streq(argv[i], "-p"))
+               else if (streq(argv[i], "-utmp_ttl"))
                {
-                       if ((i + 1) < argc) pdays = atoi(argv[++i]);
+                       if ((i + 1) < argc) global.utmp_ttl = atol(argv[++i]);
                }
-               else if (streq(argv[i], "-l"))
+               else if (streq(argv[i], "-mps_limit"))
                {
-                       if ((i + 1) < argc) mp = argv[++i];
+                       if ((i + 1) < argc) global.mps_limit = atol(argv[++i]);
                }
-               else if (streq(argv[i], "-c"))
+               else if (streq(argv[i], "-dup_delay"))
                {
-                       if ((i + 1) < argc)
-                       {
-                               i++;
-                               if ((argv[i][0] >= '0') && (argv[i][0] <= '7') && (argv[i][1] == '\0')) asl_log_filter = ASL_FILTER_MASK_UPTO(atoi(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]);
+                       if ((i + 1) < argc) global.bsd_max_dup_time = atoll(argv[++i]);
                }
+#if !TARGET_IPHONE_SIMULATOR
                else if (streq(argv[i], "-klog_in"))
                {
                        if ((i + 1) < argc) activate_klog_in = atoi(argv[++i]);
@@ -358,130 +595,144 @@ main(int argc, 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]);
+               }
+#endif
+               else if (streq(argv[i], "-launchd_in"))
+               {
+                       if ((i + 1) < argc) global.launchd_enabled = atoi(argv[++i]);
+               }
+#if !TARGET_IPHONE_SIMULATOR
                else if (streq(argv[i], "-bsd_out"))
                {
                        if ((i + 1) < argc) activate_bsd_out = atoi(argv[++i]);
                }
-               else if (streq(argv[i], "-udp_in"))
+               else if (streq(argv[i], "-remote"))
                {
-                       if ((i + 1) < argc) activate_udp_in = atoi(argv[++i]);
+                       if ((i + 1) < argc) remote_enabled = atoi(argv[++i]);
                }
+#endif
        }
 
-       TAILQ_INIT(&Moduleq);
-       static_modules();
-       load_modules(mp);
-       aslevent_init();
-
-       if (debug == 0)
+       if (global.dbtype == 0)
        {
-               if (daemonize != 0)
-               {
-                       if (fork() != 0) exit(0);
-                       
-                       detach();
-                       closeall();
-               }
-
-               writepid();
+               global.dbtype = DB_TYPE_FILE;
+               global.db_file_max = 25600000;
        }
 
-       signal(SIGHUP, catch_sighup);
-       signal(SIGWINCH, catch_sigwinch);
+       signal(SIGHUP, SIG_IGN);
 
-       FD_ZERO(&rd);
-       FD_ZERO(&wr);
-       FD_ZERO(&ex);
+       memset(tstr, 0, sizeof(tstr));
+       now = time(NULL);
+       ctime_r(&now, tstr);
+       tstr[19] = '\0';
+       asldebug("\n%s syslogd PID %d starting\n", tstr, global.pid);
 
-       for (mod = Moduleq.tqh_first; mod != NULL; mod = mod->entries.tqe_next)
-       {
-               fd = mod->init();
-               if (fd < 0) continue;
-       }
+       writepid(&first_syslogd_start);
 
-       lastmark = time(NULL);
-       notify_time = lastmark;
-       memset(&timeout, 0, sizeof(struct timeval));
-       pto = NULL;
+       /*
+        * Log UTMPX boot time record
+        */
+       write_boot_log(first_syslogd_start);
 
-       ssec = msec;
-       if (ssec > 0)
-       {
-               timeout.tv_sec = ssec;
-               pto = &timeout;
-       }
+       /* default NOTIFY_SYSTEM_MASTER settings */
+       master_val = 0x0;
+       notify_register_plain(NOTIFY_SYSTEM_MASTER, &master_token);
+       notify_set_state(master_token, master_val);
 
-       ptime = 0;
-       if (pdays > 0) ptime = lastmark + PRUNE_AFTER_START_DELAY;
+       asldebug("reading launch plist\n");
+       launch_config();
 
-       forever
-       {
-               if (pto != NULL) pto->tv_sec = ssec;
-               max = aslevent_fdsets(&rd, &wr, &ex);
+       asldebug("initializing modules\n");
+       init_modules();
 
-               status = select(max+1, &rd, &wr, &ex, pto);
+#if !TARGET_IPHONE_SIMULATOR
+       asldebug("setting up network change notification handler\n");
 
-               if (reset != 0)
-               {
-                       send_reset();
-                       reset = 0;
-               }
+       /* 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();
+       });
+#endif
 
-               if (pto != NULL)
-               {
-                       tick = time(NULL);
-                       delta = tick - lastmark;
-                       if (delta >= msec)
+       asldebug("setting up quota notification handler\n");
+
+       notify_key = NULL;
+       asprintf(&notify_key, "%s%s", NOTIFY_PATH_SERVICE, NOQUOTA_FILE_PATH);
+       if (notify_key != NULL)
+       {
+               int status;
+
+               status = notify_register_dispatch(notify_key, &quota_file_token, dispatch_get_main_queue(), ^(int t){
+                       struct stat sb;
+                       memset(&sb, 0, sizeof(sb));
+                       if (stat(NOQUOTA_FILE_PATH, &sb) == 0)
                        {
-                               lastmark = tick;
-                               aslmark();
+                               char *str = NULL;
+                               asprintf(&str, "[Sender syslogd] [Level 2] [PID %u] [Facility syslog] [Message *** MESSAGE QUOTAS DISABLED FOR ALL PROCESSES ***]", global.pid);
+                               internal_log_message(str);
+                               free(str);
                        }
-               }
-
-               if (prune != 0)
-               {
-                       asl_prune(NULL);
-                       prune = 0;
-                       ptime = 0;
-               }
-               else if (ptime != 0)
-               {
-                       tick = time(NULL);
-                       if (tick >= ptime)
+                       else
                        {
-                               pq = asl_new(ASL_TYPE_QUERY);
-                               str = NULL;
-                               asprintf(&str, "-%dd", pdays);
-                               asl_set_query(pq, ASL_KEY_TIME, str, ASL_QUERY_OP_LESS);
-                               if (str != NULL) free(str);
-                       
-                               /* asl_prune frees the query */
-                               asl_prune(pq);
-                               ptime = 0;
+                               char *str = NULL;
+                               asprintf(&str, "[Sender syslogd] [Level 2] [PID %u] [Facility syslog] [Message *** MESSAGE QUOTAS ENABLED ***]", global.pid);
+                               internal_log_message(str);
+                               free(str);
                        }
-               }
+               });
 
-               if (__notify_78945668_info__ < 0)
-               {
-                       tick = time(NULL);
-                       if (tick >= notify_time)
+               free(notify_key);
+       }
+
+       /* 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;
+
+                       asldebug("SIGHUP reset\n");
+                       for (i = 0; i < global.module_count; i++)
                        {
-                               if (notify_post("com.apple.system.syslogd") == NOTIFY_STATUS_OK) __notify_78945668_info__ = 0;
-                               else notify_time = tick + NOTIFY_DELAY;
+                               if (global.module[i]->enabled != 0) global.module[i]->reset();
                        }
-               }
+               });
+       });
 
-               if (status != 0) aslevent_handleevent(rd, wr, ex, NULL);
-       }
-}
+       dispatch_resume(global.sig_hup_src);
 
-int
-asldebug(const char *str, ...)
-{
-       va_list v;
+       /* register for DB notification (posted by dbserver) for performance */
+       notify_register_plain(kNotifyASLDBUpdate, &asl_db_token);
 
-       if (debug == 0) return 0;
+       /* timer for MARK facility */
+       if (global.mark_time > 0)
+       {
+               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_time(DISPATCH_TIME_NOW, global.mark_time * NSEC_PER_SEC), global.mark_time * NSEC_PER_SEC, 0);
+               dispatch_resume(global.mark_timer);
+       }
 
-       va_start(v, str);
-       return vprintf(str, v);
+       asldebug("starting mach service\n");
+       /*
+        * 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();
+       });
+
+       /* go to work */
+       asldebug("starting work queue\n");
+       dispatch_resume(global.work_queue);
+       dispatch_main();
+
+       /* NOTREACHED */
+       return 0;
 }