]> git.saurik.com Git - apple/launchd.git/blobdiff - launchd/src/launchd.c
launchd-392.18.tar.gz
[apple/launchd.git] / launchd / src / launchd.c
index e7acf681a49bb38db8ec8cb283df9a170f032c37..78e173826f94899d7dc40d1a2e22b8e26310ba81 100644 (file)
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
-static const char *const __rcs_file_version__ = "$Revision: 1.217 $";
+static const char *const __rcs_file_version__ = "$Revision: 24863 $";
+
+#include "config.h"
+#include "launchd.h"
 
-#include <Security/Authorization.h>
-#include <Security/AuthorizationTags.h>
-#include <Security/AuthSession.h>
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/event.h>
@@ -38,6 +38,9 @@ static const char *const __rcs_file_version__ = "$Revision: 1.217 $";
 #include <sys/ioctl.h>
 #include <sys/mount.h>
 #include <sys/kern_event.h>
+#include <sys/reboot.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
 #include <net/if.h>
 #include <netinet/in.h>
 #include <netinet/in_var.h>
@@ -46,7 +49,6 @@ static const char *const __rcs_file_version__ = "$Revision: 1.217 $";
 #include <unistd.h>
 #include <signal.h>
 #include <errno.h>
-#include <syslog.h>
 #include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -59,501 +61,501 @@ static const char *const __rcs_file_version__ = "$Revision: 1.217 $";
 #include <dlfcn.h>
 #include <dirent.h>
 #include <string.h>
+#include <setjmp.h>
+#include <spawn.h>
+#include <sched.h>
 #include <pthread.h>
+#include <util.h>
 
-#include "bootstrap_public.h"
-#include "bootstrap_private.h"
+#if HAVE_LIBAUDITD
+#include <bsm/auditd_lib.h>
+#include <bsm/audit_session.h>
+#endif
+
+#include "bootstrap.h"
+#include "vproc.h"
+#include "vproc_priv.h"
+#include "vproc_internal.h"
 #include "launch.h"
-#include "launch_priv.h"
-#include "launchd.h"
+#include "launch_internal.h"
+
+#include "launchd_runtime.h"
 #include "launchd_core_logic.h"
 #include "launchd_unix_ipc.h"
 
-#include "launchd_internalServer.h"
-#include "launchd_internal.h"
-#include "notifyServer.h"
-#include "bootstrapServer.h"
-
-union MaxRequestSize {
-       union __RequestUnion__do_notify_subsystem req;
-       union __ReplyUnion__do_notify_subsystem rep;
-       union __RequestUnion__x_launchd_internal_subsystem req2;
-       union __ReplyUnion__x_launchd_internal_subsystem rep2;
-       union __RequestUnion__x_bootstrap_subsystem req3;
-       union __ReplyUnion__x_bootstrap_subsystem rep3;
-};
-
-static boolean_t launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply);
-
-#define PID1LAUNCHD_CONF "/etc/launchd.conf"
 #define LAUNCHD_CONF ".launchd.conf"
-#define LAUNCHCTL_PATH "/bin/launchctl"
-#define SECURITY_LIB "/System/Library/Frameworks/Security.framework/Versions/A/Security"
 
 extern char **environ;
 
-static void async_callback(void);
-static void signal_callback(void *, struct kevent *);
-static void fs_callback(void);
-static void ppidexit_callback(void);
 static void pfsystem_callback(void *, struct kevent *);
 
-static kq_callback kqasync_callback = (kq_callback)async_callback;
-static kq_callback kqsignal_callback = signal_callback;
-static kq_callback kqfs_callback = (kq_callback)fs_callback;
-static kq_callback kqppidexit_callback = (kq_callback)ppidexit_callback;
 static kq_callback kqpfsystem_callback = pfsystem_callback;
 
-static void pid1_magic_init(bool sflag);
-
-static void usage(FILE *where);
+static void pid1_magic_init(void);
 
 static void testfd_or_openfd(int fd, const char *path, int flags);
 static bool get_network_state(void);
 static void monitor_networking_state(void);
-static void *kqueue_demand_loop(void *arg);
-
-static pthread_t kqueue_demand_thread;
-static int mainkq = 0;
-static int asynckq = 0;
-static bool re_exec_in_single_user_mode = false;
-static char *pending_stdout = NULL;
-static char *pending_stderr = NULL;
-static struct jobcb *rlcj = NULL;
-
-sigset_t blocked_signals = 0;
-bool shutdown_in_progress = false;
-bool network_up = false;
-int batch_disabler_count = 0;
-mach_port_t launchd_internal_port = MACH_PORT_NULL;
-mach_port_t ipc_port_set = MACH_PORT_NULL;
+static void fatal_signal_handler(int sig, siginfo_t *si, void *uap);
+static void handle_pid1_crashes_separately(void);
+static void do_pid1_crash_diagnosis_mode(const char *msg);
+static int basic_fork(void);
+static bool do_pid1_crash_diagnosis_mode2(const char *msg);
+
+static void *update_thread(void *nothing);
+
+static bool re_exec_in_single_user_mode;
+static void *crash_addr;
+static pid_t crash_pid;
+
+bool shutdown_in_progress;
+bool fake_shutdown_in_progress;
+bool network_up;
+char g_username[128] = "__Uninitialized__";
+char g_my_label[128] = "__Uninitialized__";
+char g_launchd_database_dir[PATH_MAX];
+FILE *g_console = NULL;
+int32_t g_sync_frequency = 30;
 
 int
 main(int argc, char *const *argv)
 {
-       static const int sigigns[] = { SIGHUP, SIGINT, SIGPIPE, SIGALRM,
-               SIGTERM, SIGURG, SIGTSTP, SIGTSTP, SIGCONT, /*SIGCHLD,*/
-               SIGTTIN, SIGTTOU, SIGIO, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF,
-               SIGWINCH, SIGINFO, SIGUSR1, SIGUSR2
-       };
-       bool sflag = false, dflag = false, Dflag = false;
-       mach_msg_type_number_t l2l_name_cnt = 0, l2l_port_cnt = 0;
-       name_array_t l2l_names = NULL;
-       mach_port_array_t l2l_ports = NULL;
-       char ldconf[PATH_MAX] = PID1LAUNCHD_CONF;
-       const char *h = getenv("HOME");
-       const char *session_type = NULL;
-       const char *optargs = NULL;
-       launch_data_t ldresp, ldmsg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
-       struct jobcb *fbj = NULL;
-       struct stat sb;
-       size_t i, checkin_fdcnt = 0;
-       int *checkin_fds = NULL;
-       mach_port_t req_mport = MACH_PORT_NULL;
-       mach_port_t checkin_mport = MACH_PORT_NULL;
-       int ch, ker, logopts;
-
-       /* main() phase one: sanitize the process */
-
-       if (getpid() != 1 && (ldresp = launch_msg(ldmsg)) && launch_data_get_type(ldresp) == LAUNCH_DATA_DICTIONARY) {
-               const char *ldlabel = launch_data_get_string(launch_data_dict_lookup(ldresp, LAUNCH_JOBKEY_LABEL));
-               launch_data_t tmp;
-
-               if ((tmp = launch_data_dict_lookup(ldresp, LAUNCH_JOBKEY_SOCKETS))) {
-                       if ((tmp = launch_data_dict_lookup(tmp, "LaunchIPC"))) {
-                               checkin_fdcnt = launch_data_array_get_count(tmp);
-                               checkin_fds = alloca(sizeof(int) * checkin_fdcnt);
-                               for (i = 0; i < checkin_fdcnt; i++) {
-                                       checkin_fds[i] = _fd(launch_data_get_fd(launch_data_array_get_index(tmp, i)));
-                               }
-                       }
+       bool sflag = false;
+       int ch;
+
+       testfd_or_openfd(STDIN_FILENO, _PATH_DEVNULL, O_RDONLY);
+       testfd_or_openfd(STDOUT_FILENO, _PATH_DEVNULL, O_WRONLY);
+       testfd_or_openfd(STDERR_FILENO, _PATH_DEVNULL, O_WRONLY);
+
+       if (g_use_gmalloc) {
+               if (!getenv("DYLD_INSERT_LIBRARIES")) {
+                       setenv("DYLD_INSERT_LIBRARIES", "/usr/lib/libgmalloc.dylib", 1);
+                       setenv("MALLOC_STRICT_SIZE", "1", 1);
+                       execv(argv[0], argv);
+               } else {
+                       unsetenv("DYLD_INSERT_LIBRARIES");
+                       unsetenv("MALLOC_STRICT_SIZE");
                }
-               if ((tmp = launch_data_dict_lookup(ldresp, LAUNCH_JOBKEY_MACHSERVICES))) {
-                       if ((tmp = launch_data_dict_lookup(tmp, ldlabel))) {
-                               checkin_mport = launch_data_get_machport(tmp);
-                       }
+       } else if (g_malloc_log_stacks) {
+               if (!getenv("MallocStackLogging")) {
+                       setenv("MallocStackLogging", "1", 1);
+                       execv(argv[0], argv);
+               } else {
+                       unsetenv("MallocStackLogging");
                }
-               launch_data_free(ldresp);
-       } else {
-               int sigi, fdi, dts = getdtablesize();
-               sigset_t emptyset;
-
-               for (fdi = STDERR_FILENO + 1; fdi < dts; fdi++)
-                       close(fdi);
-               for (sigi = 1; sigi < NSIG; sigi++)
-                       launchd_assumes(signal(sigi, SIG_DFL) != SIG_ERR);
-               sigemptyset(&emptyset);
-               launchd_assumes(sigprocmask(SIG_SETMASK, &emptyset, NULL) == 0);
        }
 
-       launch_data_free(ldmsg);
-
-       testfd_or_openfd(STDIN_FILENO, _PATH_DEVNULL, O_RDONLY|O_NOCTTY);
-       testfd_or_openfd(STDOUT_FILENO, _PATH_DEVNULL, O_WRONLY|O_NOCTTY);
-       testfd_or_openfd(STDERR_FILENO, _PATH_DEVNULL, O_WRONLY|O_NOCTTY);
-
-       /* main phase two: parse arguments */
-
-       if (getpid() == 1) {
-               optargs = "s";
-       } else {
-               optargs = "DS:dh";
-       }
-
-       while ((ch = getopt(argc, argv, optargs)) != -1) {
+       while ((ch = getopt(argc, argv, "s")) != -1) {
                switch (ch) {
-               case 'S': session_type = optarg; break; /* what type of session we're creating */
-               case 'D': Dflag = true;   break;        /* debug */
-               case 'd': dflag = true;   break;        /* daemonize */
-               case 's': sflag = true;   break;        /* single user */
-               case 'h': usage(stdout);  break;        /* help */
+               case 's': sflag = true; break;  /* single user */
                case '?': /* we should do something with the global optopt variable here */
                default:
-                       fprintf(stderr, "ignoring unknown arguments\n");
-                       usage(stderr);
+                       fprintf(stderr, "%s: ignoring unknown arguments\n", getprogname());
                        break;
                }
        }
-       argc -= optind;
-       argv += optind;
-
-       /* main phase three: get the party started */
-
-       if (dflag)
-               launchd_assumes(daemon(0, 0) == 0);
-
-       launchd_assert((errno = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &ipc_port_set)) == KERN_SUCCESS);
-       launchd_assert(launchd_mport_create_recv(&launchd_internal_port) == KERN_SUCCESS);
-       launchd_assert(launchd_mport_make_send(launchd_internal_port) == KERN_SUCCESS);
-       launchd_assert((errno = mach_port_move_member(mach_task_self(), launchd_internal_port, ipc_port_set)) == KERN_SUCCESS);
-
-       logopts = LOG_PID|LOG_CONS;
-       if (Dflag)
-               logopts |= LOG_PERROR;
 
-       openlog(getprogname(), logopts, LOG_LAUNCHD);
-       setlogmask(LOG_UPTO(Dflag ? LOG_DEBUG : LOG_NOTICE));
-
-       launchd_assert((mainkq = kqueue()) != -1);
-
-       launchd_assert((asynckq = kqueue()) != -1);
-       
-       launchd_assert(kevent_mod(asynckq, EVFILT_READ, EV_ADD, 0, 0, &kqasync_callback) != -1);
-
-       sigemptyset(&blocked_signals);
-
-       for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
-               launchd_assumes(kevent_mod(sigigns[i], EVFILT_SIGNAL, EV_ADD, 0, 0, &kqsignal_callback) != -1);
-               sigaddset(&blocked_signals, sigigns[i]);
-               launchd_assumes(signal(sigigns[i], SIG_IGN) != SIG_ERR);
+       if (getpid() != 1 && getppid() != 1) {
+               fprintf(stderr, "%s: This program is not meant to be run directly.\n", getprogname());
+               exit(EXIT_FAILURE);
        }
 
-       /* sigh... ignoring SIGCHLD has side effects: we can't call wait*() */
-       launchd_assert(kevent_mod(SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, &kqsignal_callback) != -1);
-
-       if (session_type && strcmp(session_type, "Aqua") == 0) {
-               mach_port_t newparent;
-
-               launchd_assert(bootstrap_parent(bootstrap_port, &newparent) == BOOTSTRAP_SUCCESS);
+       launchd_runtime_init();
 
-               launchd_assert(_launchd_to_launchd(bootstrap_port, &req_mport, &checkin_mport,
-                                       &l2l_names, &l2l_name_cnt, &l2l_ports, &l2l_port_cnt) == BOOTSTRAP_SUCCESS);
-
-               launchd_assert(l2l_name_cnt == l2l_port_cnt);
+       if (pid1_magic) {
+               int cfd = -1;
+               if (launchd_assumes((cfd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) != -1)) {
+                       _fd(cfd);
+                       if (!launchd_assumes((g_console = fdopen(cfd, "w")) != NULL)) {
+                               close(cfd);
+                       }
+               }
+       }
 
-               task_set_bootstrap_port(mach_task_self(), newparent);
-               launchd_assumes(mach_port_deallocate(mach_task_self(), bootstrap_port) == KERN_SUCCESS);
-               bootstrap_port = newparent;
+       if (NULL == getenv("PATH")) {
+               setenv("PATH", _PATH_STDPATH, 1);
        }
 
-       mach_init_init(req_mport, checkin_mport, l2l_names, l2l_ports, l2l_name_cnt);
+       if (pid1_magic) {
+               pid1_magic_init();
+       } else {
+               ipc_server_init();
+               
+               runtime_log_push();
+               
+               struct passwd *pwent = getpwuid(getuid());
+               if (pwent) {
+                       strlcpy(g_username, pwent->pw_name, sizeof(g_username) - 1);
+               }
 
-       if (h)
-               sprintf(ldconf, "%s/%s", h, LAUNCHD_CONF);
+               snprintf(g_my_label, sizeof(g_my_label), "com.apple.launchd.peruser.%u", getuid());
+               
+               auditinfo_addr_t auinfo;
+               if (launchd_assumes(getaudit_addr(&auinfo, sizeof(auinfo)) != -1)) {
+                       g_audit_session = auinfo.ai_asid;
+                       runtime_syslog(LOG_DEBUG, "Our audit session ID is %i", g_audit_session);
+               }
+               
+               g_audit_session_port = _audit_session_self();
+               snprintf(g_launchd_database_dir, sizeof(g_launchd_database_dir), LAUNCHD_DB_PREFIX "/com.apple.launchd.peruser.%u", getuid());
+               runtime_syslog(LOG_DEBUG, "Per-user launchd for UID %u (%s) has begun.", getuid(), g_username);
+       }
 
-       rlcj = job_new(root_job, READCONF_LABEL, LAUNCHCTL_PATH, NULL, ldconf, MACH_PORT_NULL);
-       launchd_assert(rlcj != NULL);
+       if (pid1_magic) {
+               runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** launchd[1] has started up. ***");
+               if (g_use_gmalloc) {
+                       runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Using libgmalloc. ***");
+               }
+               if (g_malloc_log_stacks) {
+                       runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Logging stacks of malloc(3) allocations. ***");
+               }
 
-       if (argv[0])
-               fbj = job_new(root_job, FIRSTBORN_LABEL, NULL, (const char *const *)argv, NULL, MACH_PORT_NULL);
+               if (g_verbose_boot) {
+                       runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Verbose boot, will log to /dev/console. ***");
+               }
 
-       if (NULL == getenv("PATH"))
-               setenv("PATH", _PATH_STDPATH, 1);
+               if (g_shutdown_debugging) {
+                       runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Shutdown debugging is enabled. ***");
+               }
 
-       if (getpid() == 1) {
-               pid1_magic_init(sflag);
+               /* PID 1 doesn't have a flat namespace. */
+               g_flat_mach_namespace = false;
        } else {
-               ipc_server_init(checkin_fds, checkin_fdcnt);
+               if (g_use_gmalloc) {
+                       runtime_syslog(LOG_NOTICE, "*** Per-user launchd using libgmalloc. ***");
+               }
        }
 
        monitor_networking_state();
 
-       /* do this after pid1_magic_init() to not catch ourselves mounting stuff */
-       launchd_assumes(kevent_mod(0, EVFILT_FS, EV_ADD, 0, 0, &kqfs_callback) != -1);
+       if (pid1_magic) {
+               handle_pid1_crashes_separately();
+       } else {
+       #if !TARGET_OS_EMBEDDED
+               /* prime shared memory before the 'bootstrap_port' global is set to zero */
+               _vproc_transaction_begin();
+               _vproc_transaction_end();
+       #endif
+       }
 
-       if (session_type) {
-               pid_t pp = getppid();
+       if (pid1_magic) {
+               /* Start the update thread -- rdar://problem/5039559&6153301 */
+               pthread_t t = NULL;
+               int err = pthread_create(&t, NULL, update_thread, NULL);
+               (void)launchd_assumes(err == 0);
+               (void)launchd_assumes(pthread_detach(t) == 0);
+       }
 
-               /* As a per session launchd, we need to exit if our parent dies.
-                *
-                * Normally, in Unix, SIGHUP would cause us to exit, but we're a
-                * daemon, and daemons use SIGHUP to signal the need to reread
-                * configuration files. "Weee."
-                */
+       jobmgr_init(sflag);
+       
+       launchd_runtime_init2();
 
-               if (pp == 1)
-                       exit(EXIT_SUCCESS);
+       launchd_runtime();
+}
 
-               ker = kevent_mod(pp, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, &kqppidexit_callback);
+void
+handle_pid1_crashes_separately(void)
+{
+       struct sigaction fsa;
+
+       fsa.sa_sigaction = fatal_signal_handler;
+       fsa.sa_flags = SA_SIGINFO;
+       sigemptyset(&fsa.sa_mask);
+
+       (void)launchd_assumes(sigaction(SIGILL, &fsa, NULL) != -1);
+       (void)launchd_assumes(sigaction(SIGFPE, &fsa, NULL) != -1);
+       (void)launchd_assumes(sigaction(SIGBUS, &fsa, NULL) != -1);
+       (void)launchd_assumes(sigaction(SIGSEGV, &fsa, NULL) != -1);
+       (void)launchd_assumes(sigaction(SIGABRT, &fsa, NULL) != -1);
+       (void)launchd_assumes(sigaction(SIGTRAP, &fsa, NULL) != -1);
+}
 
-               if (ker == -1)
-                       exit(launchd_assumes(errno == ESRCH) ? EXIT_SUCCESS : EXIT_FAILURE);
+void *update_thread(void *nothing __attribute__((unused)))
+{
+       /* <rdar://problem/7385963> use IOPOL_PASSIVE for sync thread */
+       (void)launchd_assumes(setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, IOPOL_PASSIVE) != -1);
+       
+       while( g_sync_frequency ) {
+               sync();
+               sleep(g_sync_frequency);
        }
+       
+       runtime_syslog(LOG_DEBUG, "Update thread exiting.");
+       return NULL;
+}
 
-       if (stat(ldconf, &sb) == 0)
-               job_start(rlcj);
-
-       if (fbj)
-               job_start(fbj);
-
-       pthread_attr_t attr;
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-       pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
-       launchd_assert(pthread_create(&kqueue_demand_thread, &attr, kqueue_demand_loop, NULL) == 0);
-       pthread_attr_destroy(&attr); 
+#define PID1_CRASH_LOGFILE "/var/log/launchd-pid1.crash"
 
-       mach_msg_return_t msgr;
-       mach_msg_size_t mxmsgsz = sizeof(union MaxRequestSize) + MAX_TRAILER_SIZE;
+/* This hack forces the dynamic linker to resolve these symbols ASAP */
+static __attribute__((unused)) typeof(sync) *__junk_dyld_trick1 = sync;
+static __attribute__((unused)) typeof(sleep) *__junk_dyld_trick2 = sleep;
+static __attribute__((unused)) typeof(reboot) *__junk_dyld_trick3 = reboot;
 
-       if (getpid() == 1 && !job_active(rlcj))
-               init_pre_kevent();
+void
+do_pid1_crash_diagnosis_mode(const char *msg)
+{
+       if (g_wsp) {
+               kill(g_wsp, SIGKILL);
+               sleep(3);
+               g_wsp = 0;
+       }
 
-       for (;;) {
-               msgr = mach_msg_server(launchd_internal_demux, mxmsgsz, ipc_port_set,
-                               MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) |
-                               MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
-               launchd_assumes(msgr == MACH_MSG_SUCCESS);
+       while (g_shutdown_debugging && !do_pid1_crash_diagnosis_mode2(msg)) {
+               sleep(1);
        }
 }
 
-void *
-kqueue_demand_loop(void *arg __attribute__((unused)))
+int
+basic_fork(void)
 {
-       fd_set rfds;
+       int wstatus = 0;
+       pid_t p;
+       
+       switch ((p = fork())) {
+       case -1:
+               runtime_syslog(LOG_ERR | LOG_CONSOLE, "Can't fork PID 1 copy for crash debugging: %m");
+               return p;
+       case 0:
+               return p;
+       default:
+               do {
+                       (void)waitpid(p, &wstatus, 0);
+               } while(!WIFEXITED(wstatus));
 
-       for (;;) {
-               FD_ZERO(&rfds);
-               FD_SET(mainkq, &rfds);
-               if (launchd_assumes(select(mainkq + 1, &rfds, NULL, NULL, NULL) == 1))
-                       launchd_assumes(handle_kqueue(launchd_internal_port, mainkq) == 0);
-       }
+               fprintf(stdout, "PID 1 copy: exit status: %d\n", WEXITSTATUS(wstatus));
 
-       return NULL;
+               return 1;
+       }
+       
+       return -1;
 }
 
-kern_return_t
-x_handle_kqueue(mach_port_t junk __attribute__((unused)), integer_t fd)
+bool
+do_pid1_crash_diagnosis_mode2(const char *msg)
 {
-       struct timespec ts = { 0, 0 };
-       struct kevent kev;
-       int kevr;
-
-       launchd_assumes((kevr = kevent(fd, NULL, 0, &kev, 1, &ts)) != -1);
-
-       if (kevr == 1)
-               (*((kq_callback *)kev.udata))(kev.udata, &kev);
-
-       if (shutdown_in_progress && total_children == 0) {
-               mach_init_reap();
-
-               shutdown_in_progress = false;
-
-               if (getpid() != 1) {
-                       exit(EXIT_SUCCESS);
-               } else if (re_exec_in_single_user_mode) {
-                       re_exec_in_single_user_mode = false;
-                       launchd_assumes(execl("/sbin/launchd", "/sbin/launchd", "-s", NULL) != -1);
+       if (basic_fork() == 0) {
+               /* Neuter our bootstrap port so that the shell doesn't try talking to us while
+                * we're blocked waiting on it.
+                */
+               if (g_console) {
+                       fflush(g_console);
                }
+               task_set_bootstrap_port(mach_task_self(), MACH_PORT_NULL);
+               if (basic_fork() != 0) {
+                       if (g_console) {
+                               fflush(g_console);
+                       }
+                       return true;
+               }
+       } else {
+               return true;
        }
-
-       if (getpid() == 1) {
-               if (rlcj && job_active(rlcj))
-                       goto out;
-               init_pre_kevent();
+       
+       int fd;
+       revoke(_PATH_CONSOLE);
+       if ((fd = open(_PATH_CONSOLE, O_RDWR)) == -1) {
+               _exit(2);
        }
-
-out:
-       return 0;
+       if (login_tty(fd) == -1) {
+               _exit(3);
+       }
+       setenv("TERM", "vt100", 1);
+       fprintf(stdout, "\n");
+       fprintf(stdout, "Entering launchd PID 1 debugging mode...\n");
+       fprintf(stdout, "The PID 1 launchd has crashed %s.\n", msg);
+       fprintf(stdout, "It has fork(2)ed itself for debugging.\n");
+       fprintf(stdout, "To debug the crashing thread of PID 1:\n");
+       fprintf(stdout, "    gdb attach %d\n", getppid());
+       fprintf(stdout, "To exit this shell and shut down:\n");
+       fprintf(stdout, "    kill -9 1\n");
+       fprintf(stdout, "A sample of PID 1 has been written to %s\n", PID1_CRASH_LOGFILE);
+       fprintf(stdout, "\n");
+       fflush(stdout);
+       
+       execl(_PATH_BSHELL, "-sh", NULL);
+       syslog(LOG_ERR, "can't exec %s for PID 1 crash debugging: %m", _PATH_BSHELL);
+       _exit(EXIT_FAILURE);
 }
 
 void
-pid1_magic_init(bool sflag)
+fatal_signal_handler(int sig, siginfo_t *si, void *uap __attribute__((unused)))
 {
-       launchd_assumes(setsid() != -1);
-       launchd_assumes(chdir("/") != -1);
-       launchd_assumes(setlogin("root") != -1);
-       launchd_assumes(mount("fdesc", "/dev", MNT_UNION, NULL) != -1);
+       const char *doom_why = "at instruction";
+       char msg[128];
+       char *sample_args[] = { "/usr/bin/sample", "1", "1", "-file", PID1_CRASH_LOGFILE, NULL };
+       pid_t sample_p;
+       int wstatus;
+
+       crash_addr = si->si_addr;
+       crash_pid = si->si_pid;
+       
+       unlink(PID1_CRASH_LOGFILE);
 
-       init_boot(sflag);
-}
+       switch ((sample_p = vfork())) {
+       case 0:
+               execve(sample_args[0], sample_args, environ);
+               _exit(EXIT_FAILURE);
+               break;
+       default:
+               waitpid(sample_p, &wstatus, 0);
+               break;
+       case -1:
+               break;
+       }
 
+       switch (sig) {
+       default:
+       case 0:
+               break;
+       case SIGBUS:
+       case SIGSEGV:
+               doom_why = "trying to read/write";
+       case SIGILL:
+       case SIGFPE:
+               snprintf(msg, sizeof(msg), "%s: %p (%s sent by PID %u)", doom_why, crash_addr, strsignal(sig), crash_pid);
+               sync();
+               do_pid1_crash_diagnosis_mode(msg);
+               sleep(3);
+               reboot(0);
+               break;
+       }
+}
 
 void
-usage(FILE *where)
+pid1_magic_init(void)
 {
-       const char *opts = "[-d]";
-
-       if (getuid() == 0)
-               opts = "[-d] [-S <type> -U <user>]";
-
-       fprintf(where, "%s: %s [-- command [args ...]]\n", getprogname(), opts);
-
-       fprintf(where, "\t-d          Daemonize.\n");
-       fprintf(where, "\t-h          This usage statement.\n");
-
-       if (getuid() == 0) {
-               fprintf(where, "\t-S <type>   What type of session to create (Aqua, tty or X11).\n");
-               fprintf(where, "\t-U <user>   Which user to create the session as.\n");
+       (void)launchd_assumes(setsid() != -1);
+       (void)launchd_assumes(chdir("/") != -1);
+       (void)launchd_assumes(setlogin("root") != -1);
+       
+       strcpy(g_my_label, "com.apple.launchd");
+
+#if !TARGET_OS_EMBEDDED
+       auditinfo_addr_t auinfo = {
+               .ai_termid = { .at_type = AU_IPv4 },
+               .ai_asid = AU_ASSIGN_ASID,
+               .ai_auid = AU_DEFAUDITID,
+               .ai_flags = AU_SESSION_FLAG_IS_INITIAL,
+       };
+       
+       if (!launchd_assumes(setaudit_addr(&auinfo, sizeof(auinfo)) != -1)) {
+               runtime_syslog(LOG_WARNING | LOG_CONSOLE, "Could not set audit session: %s.", strerror(errno));
+               _exit(EXIT_FAILURE);
        }
 
-       if (where == stdout)
-               exit(EXIT_SUCCESS);
+       g_audit_session = auinfo.ai_asid;
+       runtime_syslog(LOG_DEBUG, "Audit Session ID: %i", g_audit_session);
+
+       g_audit_session_port = _audit_session_self();
+#endif
+       
+       strcpy(g_launchd_database_dir, LAUNCHD_DB_PREFIX "/com.apple.launchd");
 }
 
-int
-kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata)
+char *
+launchd_data_base_path(int db_type)
 {
-       struct kevent kev;
-       int q = mainkq;
-
-       if (EVFILT_TIMER == filter || EVFILT_VNODE == filter)
-               q = asynckq;
-
-       if (flags & EV_ADD && !launchd_assumes(udata != NULL)) {
-               errno = EINVAL;
-               return -1;
+       static char result[PATH_MAX];
+       static int last_db_type = -1;
+       
+       if (db_type == last_db_type) {
+               return result;
        }
-
-       EV_SET(&kev, ident, filter, flags, fflags, data, udata);
-       return kevent(q, &kev, 1, NULL, 0, NULL);
+       
+       switch (db_type) {
+               case LAUNCHD_DB_TYPE_OVERRIDES  :
+                       snprintf(result, sizeof(result), "%s/%s", g_launchd_database_dir, "overrides.plist");
+                       last_db_type = db_type;
+                       break;
+               case LAUNCHD_DB_TYPE_JOBCACHE   :
+                       snprintf(result, sizeof(result), "%s/%s", g_launchd_database_dir, "jobcache.launchdata");
+                       last_db_type = db_type;
+                       break;
+               default                                                 :
+                       break;
+       }
+       
+       return result;
 }
 
 int
 _fd(int fd)
 {
-       if (fd >= 0)
-               launchd_assumes(fcntl(fd, F_SETFD, 1) != -1);
+       if (fd >= 0) {
+               (void)launchd_assumes(fcntl(fd, F_SETFD, 1) != -1);
+       }
        return fd;
 }
 
 void
-ppidexit_callback(void)
+launchd_shutdown(void)
 {
-       launchd_shutdown();
+       int64_t now;
 
-       /* Let's just bail for now. We should really try to wait for jobs to exit first. */
-       exit(EXIT_SUCCESS);
-}
+       if (shutdown_in_progress) {
+               return;
+       }
+
+       runtime_ktrace0(RTKT_LAUNCHD_EXITING);
 
-void
-launchd_shutdown(void)
-{
        shutdown_in_progress = true;
 
-       launchd_assumes(close(asynckq) != -1);
-       
-       rlcj = NULL;
+       if (pid1_magic || g_log_per_user_shutdown) {
+               /*
+                * When this changes to a more sustainable API, update this:
+                * http://howto.apple.com/db.cgi?Debugging_Apps_Non-Responsive_At_Shutdown
+                */
+               runtime_setlogmask(LOG_UPTO(LOG_DEBUG));
+       }
 
-       job_remove_all_inactive(root_job);
+       runtime_log_push();
 
-       if (getpid() == 1)
-               catatonia();
-}
+       now = runtime_get_wall_time();
 
-void
-launchd_single_user(void)
-{
-       int tries;
+       char *term_who = pid1_magic ? "System shutdown" : "Per-user launchd termination for ";
+       runtime_syslog(LOG_INFO, "%s%s began", term_who, pid1_magic ? "" : g_username);
 
-       launchd_shutdown();
-
-       kill(-1, SIGTERM);
+       launchd_assert(jobmgr_shutdown(root_jobmgr) != NULL);
 
-       for (tries = 0; tries < 10; tries++) {
-               sleep(1);
-               if (kill(-1, 0) == -1 && errno == ESRCH)
-                       goto out;
+#if HAVE_LIBAUDITD
+       if (pid1_magic) {
+               (void)launchd_assumes(audit_quick_stop() == 0);
        }
+#endif
+}
 
-       syslog(LOG_WARNING, "Gave up waiting for processes to exit while going to single user mode, sending SIGKILL");
-       kill(-1, SIGKILL);
+void
+launchd_single_user(void)
+{
+       runtime_syslog(LOG_NOTICE, "Going to single-user mode");
 
-out:
        re_exec_in_single_user_mode = true;
-}
 
-static void signal_callback(void *obj __attribute__((unused)), struct kevent *kev)
-{
-       switch (kev->ident) {
-       case SIGHUP:
-               if (rlcj)
-                       job_start(rlcj);
-               break;
-       case SIGTERM:
-               launchd_shutdown();
-               break;
-       default:
-               break;
-       } 
-}
+       launchd_shutdown();
 
-void
-fs_callback(void)
-{
-       if (pending_stdout) {
-               int fd = open(pending_stdout, O_CREAT|O_APPEND|O_WRONLY|O_NOCTTY, DEFFILEMODE);
-               if (fd != -1) {
-                       launchd_assumes(dup2(fd, STDOUT_FILENO) != -1);
-                       launchd_assumes(close(fd) == 0);
-                       free(pending_stdout);
-                       pending_stdout = NULL;
-               }
-       }
-       if (pending_stderr) {
-               int fd = open(pending_stderr, O_CREAT|O_APPEND|O_WRONLY|O_NOCTTY, DEFFILEMODE);
-               if (fd != -1) {
-                       launchd_assumes(dup2(fd, STDERR_FILENO) != -1);
-                       launchd_assumes(close(fd) == 0);
-                       free(pending_stderr);
-                       pending_stderr = NULL;
-               }
-       }
+       sleep(3);
 
-       ipc_server_init(NULL, 0);
+       runtime_kill(-1, SIGKILL);
 }
 
 void
 launchd_SessionCreate(void)
 {
-       OSStatus (*sescr)(SessionCreationFlags flags, SessionAttributeBits attributes);
-       void *seclib;
-
-       if (launchd_assumes((seclib = dlopen(SECURITY_LIB, RTLD_LAZY)) != NULL)) {
-               if (launchd_assumes((sescr = dlsym(seclib, "SessionCreate")) != NULL))
-                       launchd_assumes(sescr(0, 0) == noErr);
-               launchd_assumes(dlclose(seclib) != -1);
+#if !TARGET_OS_EMBEDDED
+       auditinfo_addr_t auinfo = {
+               .ai_termid = { .at_type = AU_IPv4 },
+               .ai_asid = AU_ASSIGN_ASID,
+               .ai_auid = getuid(),
+               .ai_flags = 0,
+       };
+       if (launchd_assumes(setaudit_addr(&auinfo, sizeof(auinfo)) == 0)) {
+               char session[16];
+               snprintf(session, sizeof(session), "%x", auinfo.ai_asid);
+               setenv("SECURITYSESSIONID", session, 1);
+       } else {
+               runtime_syslog(LOG_WARNING, "Could not set audit session: %s.", strerror(errno));
        }
-}
-
-void
-async_callback(void)
-{
-       struct timespec timeout = { 0, 0 };
-       struct kevent kev;
-
-       if (launchd_assumes(kevent(asynckq, NULL, 0, &kev, 1, &timeout) == 1))
-               (*((kq_callback *)kev.udata))(kev.udata, &kev);
+#endif
 }
 
 void
@@ -562,71 +564,44 @@ testfd_or_openfd(int fd, const char *path, int flags)
        int tmpfd;
 
        if (-1 != (tmpfd = dup(fd))) {
-               launchd_assumes(close(tmpfd) == 0);
+               (void)launchd_assumes(runtime_close(tmpfd) == 0);
        } else {
-               if (-1 == (tmpfd = open(path, flags))) {
-                       syslog(LOG_ERR, "open(\"%s\", ...): %m", path);
+               if (-1 == (tmpfd = open(path, flags | O_NOCTTY, DEFFILEMODE))) {
+                       runtime_syslog(LOG_ERR, "open(\"%s\", ...): %m", path);
                } else if (tmpfd != fd) {
-                       launchd_assumes(dup2(tmpfd, fd) != -1);
-                       launchd_assumes(close(tmpfd) == 0);
+                       (void)launchd_assumes(dup2(tmpfd, fd) != -1);
+                       (void)launchd_assumes(runtime_close(tmpfd) == 0);
                }
        }
 }
 
-launch_data_t                   
-launchd_setstdio(int d, launch_data_t o)
-{
-       launch_data_t resp = launch_data_new_errno(0);
-
-       if (launch_data_get_type(o) == LAUNCH_DATA_STRING) {
-               char **where = &pending_stderr;
-
-               if (d == STDOUT_FILENO)
-                       where = &pending_stdout;
-               if (*where)
-                       free(*where);
-               *where = strdup(launch_data_get_string(o));
-       } else if (launch_data_get_type(o) == LAUNCH_DATA_FD) {
-               launchd_assumes(dup2(launch_data_get_fd(o), d) != -1);
-       } else {
-               launch_data_set_errno(resp, EINVAL);
-       }
-
-       return resp;
-}
-
-void
-batch_job_enable(bool e, struct conncb *c)
-{
-       if (e && c->disabled_batch) {
-               batch_disabler_count--;
-               c->disabled_batch = 0;
-               if (batch_disabler_count == 0)
-                       kevent_mod(asynckq, EVFILT_READ, EV_ENABLE, 0, 0, &kqasync_callback);
-       } else if (!e && !c->disabled_batch) {
-               if (batch_disabler_count == 0)
-                       kevent_mod(asynckq, EVFILT_READ, EV_DISABLE, 0, 0, &kqasync_callback);
-               batch_disabler_count++;
-               c->disabled_batch = 1;
-       }
-}
-
 bool
 get_network_state(void)
 {
        struct ifaddrs *ifa, *ifai;
        bool up = false;
+       int r;
+
+       /* Workaround 4978696: getifaddrs() reports false ENOMEM */
+       while ((r = getifaddrs(&ifa)) == -1 && errno == ENOMEM) {
+               runtime_syslog(LOG_DEBUG, "Worked around bug: 4978696");
+               (void)launchd_assumes(sched_yield() != -1);
+       }
 
-       if (!launchd_assumes(getifaddrs(&ifa) != -1))
+       if (!launchd_assumes(r != -1)) {
                return network_up;
+       }
 
        for (ifai = ifa; ifai; ifai = ifai->ifa_next) {
-               if (!(ifai->ifa_flags & IFF_UP))
+               if (!(ifai->ifa_flags & IFF_UP)) {
                        continue;
-               if (ifai->ifa_flags & IFF_LOOPBACK)
+               }
+               if (ifai->ifa_flags & IFF_LOOPBACK) {
                        continue;
-               if (ifai->ifa_addr->sa_family != AF_INET && ifai->ifa_addr->sa_family != AF_INET6)
+               }
+               if (ifai->ifa_addr->sa_family != AF_INET && ifai->ifa_addr->sa_family != AF_INET6) {
                        continue;
+               }
                up = true;
                break;
        }
@@ -644,34 +619,35 @@ monitor_networking_state(void)
 
        network_up = get_network_state();
 
-       if (!launchd_assumes(pfs != -1))
+       if (!launchd_assumes(pfs != -1)) {
                return;
+       }
 
        memset(&kev_req, 0, sizeof(kev_req));
        kev_req.vendor_code = KEV_VENDOR_APPLE;
        kev_req.kev_class = KEV_NETWORK_CLASS;
 
        if (!launchd_assumes(ioctl(pfs, SIOCSKEVFILT, &kev_req) != -1)) {
-               close(pfs);
+               runtime_close(pfs);
                return;
        }
 
-       launchd_assumes(kevent_mod(pfs, EVFILT_READ, EV_ADD, 0, 0, &kqpfsystem_callback) != -1);
+       (void)launchd_assumes(kevent_mod(pfs, EVFILT_READ, EV_ADD, 0, 0, &kqpfsystem_callback) != -1);
 }
 
 void
-pfsystem_callback(void *obj, struct kevent *kev)
+pfsystem_callback(void *obj __attribute__((unused)), struct kevent *kev)
 {
        bool new_networking_state;
        char buf[1024];
 
-       launchd_assumes(read(kev->ident, &buf, sizeof(buf)) != -1);
+       (void)launchd_assumes(read((int)kev->ident, &buf, sizeof(buf)) != -1);
 
        new_networking_state = get_network_state();
 
        if (new_networking_state != network_up) {
                network_up = new_networking_state;
-               job_dispatch_all_other_semaphores(root_job, NULL);
+               jobmgr_dispatch_all_semaphores(root_jobmgr);
        }
 }
 
@@ -683,6 +659,8 @@ _log_launchd_bug(const char *rcs_rev, const char *path, unsigned int line, const
        const char *file = strrchr(path, '/');
        char *rcs_rev_tmp = strchr(rcs_rev, ' ');
 
+       runtime_ktrace1(RTKT_LAUNCHD_BUG);
+
        if (!file) {
                file = path;
        } else {
@@ -694,53 +672,10 @@ _log_launchd_bug(const char *rcs_rev, const char *path, unsigned int line, const
        } else {
                strlcpy(buf, rcs_rev_tmp + 1, sizeof(buf));
                rcs_rev_tmp = strchr(buf, ' ');
-               if (rcs_rev_tmp)
+               if (rcs_rev_tmp) {
                        *rcs_rev_tmp = '\0';
-       }
-
-       syslog(LOG_NOTICE, "Bug: %s:%u (%s):%u: %s", file, line, buf, saved_errno, test);
-}
-
-bool
-progeny_check(pid_t p)
-{
-       pid_t selfpid = getpid();
-
-       while (p != selfpid && p != 1) {
-               int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, p };
-               size_t miblen = sizeof(mib) / sizeof(mib[0]);
-               struct kinfo_proc kp;
-               size_t kplen = sizeof(kp);
-
-               if (launchd_assumes(sysctl(mib, miblen, &kp, &kplen, NULL, 0) != -1)
-                               && launchd_assumes(kplen == sizeof(kp))) {
-                       p = kp.kp_eproc.e_ppid;
-               } else {
-                       return false;
                }
        }
 
-       if (p == selfpid)
-               return true;
-
-       return false;
-}
-
-boolean_t
-launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply)
-{
-       if (gc_this_job) {
-               job_remove(gc_this_job);
-               gc_this_job = NULL;
-       }
-
-       if (Request->msgh_local_port == launchd_internal_port) {
-               if (launchd_internal_server_routine(Request))
-                       return launchd_internal_server(Request, Reply);
-       } else {
-               if (bootstrap_server_routine(Request))
-                       return bootstrap_server(Request, Reply);
-       }
-
-       return notify_server(Request, Reply);
+       runtime_syslog(LOG_NOTICE, "Bug: %s:%u (%s):%u: %s", file, line, buf, saved_errno, test);
 }