]> git.saurik.com Git - apple/launchd.git/commitdiff
launchd-392.18.tar.gz mac-os-x-107 mac-os-x-1071 v392.18
authorApple <opensource@apple.com>
Wed, 13 Jul 2011 22:38:10 +0000 (22:38 +0000)
committerApple <opensource@apple.com>
Wed, 13 Jul 2011 22:38:10 +0000 (22:38 +0000)
39 files changed:
launchd.xcodeproj/project.pbxproj
launchd/src/IPC.h
launchd/src/StartupItems.c
launchd/src/StartupItems.h
launchd/src/SystemStarter.c
launchd/src/SystemStarter.h
launchd/src/SystemStarterIPC.h
launchd/src/bootstrap.h
launchd/src/bootstrap_priv.h
launchd/src/com.apple.SystemStarter.plist
launchd/src/config.h
launchd/src/launch.h
launchd/src/launch_internal.h
launchd/src/launch_priv.h
launchd/src/launchctl.c
launchd/src/launchd.c
launchd/src/launchd.h
launchd/src/launchd.plist.5
launchd/src/launchd_core_logic.c
launchd/src/launchd_core_logic.h
launchd/src/launchd_helper.defs [new file with mode: 0644]
launchd/src/launchd_internal.defs
launchd/src/launchd_ktrace.h
launchd/src/launchd_mig_types.defs
launchd/src/launchd_runtime.c
launchd/src/launchd_runtime.h
launchd/src/launchd_unix_ipc.c
launchd/src/launchd_unix_ipc.h
launchd/src/launchproxy.c
launchd/src/libbootstrap.c
launchd/src/liblaunch.c
launchd/src/libvproc.c
launchd/src/protocol_job_forward.defs
launchd/src/protocol_job_reply.defs
launchd/src/protocol_vproc.defs
launchd/src/rc.netboot
launchd/src/vproc.h
launchd/src/vproc_internal.h
launchd/src/vproc_priv.h

index 5b20b534aba15cc2c3c6716faa4c46e183fb9614..0218d29125552bb11b8cabd95fc56e9e72638813 100644 (file)
@@ -3,7 +3,7 @@
        archiveVersion = 1;
        classes = {
        };
        archiveVersion = 1;
        classes = {
        };
-       objectVersion = 45;
+       objectVersion = 46;
        objects = {
 
 /* Begin PBXAggregateTarget section */
        objects = {
 
 /* Begin PBXAggregateTarget section */
@@ -50,6 +50,8 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+               4B0A3103131F266E002DE2E5 /* events.defs in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A30FF131F24AC002DE2E5 /* events.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+               4B0FB8EA1241FE3F00383109 /* domain.defs in Sources */ = {isa = PBXBuildFile; fileRef = 4B0FB8E91241FE3F00383109 /* domain.defs */; settings = {ATTRIBUTES = (Server, ); }; };
                4B10F1B90F43BE7E00875782 /* launchd_internal.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC59A0BD0E8C8A2A00D41150 /* launchd_internal.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
                4B10F1BA0F43BE7E00875782 /* protocol_vproc.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC3627DF0E9344BF0054F1A3 /* protocol_vproc.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
                4B10F1BB0F43BE7E00875782 /* protocol_job_reply.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC3629160E9348390054F1A3 /* protocol_job_reply.defs */; };
                4B10F1B90F43BE7E00875782 /* launchd_internal.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC59A0BD0E8C8A2A00D41150 /* launchd_internal.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
                4B10F1BA0F43BE7E00875782 /* protocol_vproc.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC3627DF0E9344BF0054F1A3 /* protocol_vproc.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
                4B10F1BB0F43BE7E00875782 /* protocol_job_reply.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC3629160E9348390054F1A3 /* protocol_job_reply.defs */; };
                4B10F1EC0F43BF5C00875782 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FCD713730E95DE49001B0111 /* libedit.dylib */; settings = {ATTRIBUTES = (Weak, ); }; };
                4B10F1EF0F43BF5C00875782 /* launchctl.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC59A0AD0E8C8A0E00D41150 /* launchctl.1 */; };
                4B1D92010F8BDE7D00125940 /* launchd.ops in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B1D91ED0F8BDE1A00125940 /* launchd.ops */; };
                4B10F1EC0F43BF5C00875782 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FCD713730E95DE49001B0111 /* libedit.dylib */; settings = {ATTRIBUTES = (Weak, ); }; };
                4B10F1EF0F43BF5C00875782 /* launchctl.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC59A0AD0E8C8A0E00D41150 /* launchctl.1 */; };
                4B1D92010F8BDE7D00125940 /* launchd.ops in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B1D91ED0F8BDE1A00125940 /* launchd.ops */; };
+               4B287733111A509400C07B35 /* launchd_helper.defs in Sources */ = {isa = PBXBuildFile; fileRef = 4B287732111A509400C07B35 /* launchd_helper.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
+               4B28781B111A61A400C07B35 /* launchd_helper.defs in Sources */ = {isa = PBXBuildFile; fileRef = 4B287732111A509400C07B35 /* launchd_helper.defs */; };
+               4B9A1C1F132759F700019C67 /* events.defs in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A30FF131F24AC002DE2E5 /* events.defs */; settings = {ATTRIBUTES = (Server, ); }; };
                4B9EDCA20EAFC77E00A78496 /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */; };
                4B9EDCA20EAFC77E00A78496 /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */; };
+               4BA2F5FD1243063D00C2AADD /* init.defs in Sources */ = {isa = PBXBuildFile; fileRef = 4BA2F5FC1243063D00C2AADD /* init.defs */; };
+               4BF8727C1187A5F000CC7DB5 /* launchd_helper.defs in Sources */ = {isa = PBXBuildFile; fileRef = 4B287732111A509400C07B35 /* launchd_helper.defs */; };
                7215DE4C0EFAF2EC00ABD81E /* libauditd.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */; };
                7215DE4C0EFAF2EC00ABD81E /* libauditd.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */; };
-               721FBEBC0EA7AE2F0057462B /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 721FBEBB0EA7AE2F0057462B /* Security.framework */; };
                726055EC0EA7EC2400D65FE7 /* mach_exc.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC36291F0E9349410054F1A3 /* mach_exc.defs */; settings = {ATTRIBUTES = (Server, ); }; };
                726056090EA7FCF200D65FE7 /* launchd_ktrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 72FDB15D0EA7D7B200B2AC84 /* launchd_ktrace.c */; };
                72AFE8090EFAF3D9004BDA46 /* libauditd.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */; };
                726055EC0EA7EC2400D65FE7 /* mach_exc.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC36291F0E9349410054F1A3 /* mach_exc.defs */; settings = {ATTRIBUTES = (Server, ); }; };
                726056090EA7FCF200D65FE7 /* launchd_ktrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 72FDB15D0EA7D7B200B2AC84 /* launchd_ktrace.c */; };
                72AFE8090EFAF3D9004BDA46 /* libauditd.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */; };
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+               4B0A30FF131F24AC002DE2E5 /* events.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 4; name = events.defs; path = /usr/local/include/xpc/events.defs; sourceTree = SDKROOT; };
+               4B0A3100131F24AC002DE2E5 /* types.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 4; name = types.defs; path = /usr/local/include/xpc/types.defs; sourceTree = SDKROOT; };
+               4B0FB8E91241FE3F00383109 /* domain.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 4; name = domain.defs; path = /usr/local/include/xpc/domain.defs; sourceTree = SDKROOT; };
                4B10F1D30F43BE7E00875782 /* launchd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = launchd; sourceTree = BUILT_PRODUCTS_DIR; };
                4B10F1F30F43BF5C00875782 /* launchctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = launchctl; sourceTree = BUILT_PRODUCTS_DIR; };
                4B1D91ED0F8BDE1A00125940 /* launchd.ops */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = launchd.ops; path = launchd/src/launchd.ops; sourceTree = "<group>"; };
                4B10F1D30F43BE7E00875782 /* launchd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = launchd; sourceTree = BUILT_PRODUCTS_DIR; };
                4B10F1F30F43BF5C00875782 /* launchctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = launchctl; sourceTree = BUILT_PRODUCTS_DIR; };
                4B1D91ED0F8BDE1A00125940 /* launchd.ops */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = launchd.ops; path = launchd/src/launchd.ops; sourceTree = "<group>"; };
+               4B287732111A509400C07B35 /* launchd_helper.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = launchd_helper.defs; path = launchd/src/launchd_helper.defs; sourceTree = "<group>"; };
                4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = /System/Library/Frameworks/DiskArbitration.framework; sourceTree = "<absolute>"; };
                4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = /System/Library/Frameworks/DiskArbitration.framework; sourceTree = "<absolute>"; };
+               4BA2F5FC1243063D00C2AADD /* init.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 4; name = init.defs; path = /usr/local/include/xpc/init.defs; sourceTree = SDKROOT; };
                7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libauditd.dylib; path = /usr/lib/libauditd.dylib; sourceTree = "<absolute>"; };
                721FBEA50EA7ABC40057462B /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config.h; path = launchd/src/config.h; sourceTree = "<group>"; };
                7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libauditd.dylib; path = /usr/lib/libauditd.dylib; sourceTree = "<absolute>"; };
                721FBEA50EA7ABC40057462B /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config.h; path = launchd/src/config.h; sourceTree = "<group>"; };
-               721FBEBB0EA7AE2F0057462B /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
                72FDB15D0EA7D7B200B2AC84 /* launchd_ktrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd_ktrace.c; path = launchd/src/launchd_ktrace.c; sourceTree = "<group>"; };
                72FDB15E0EA7D7B200B2AC84 /* launchd_ktrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd_ktrace.h; path = launchd/src/launchd_ktrace.h; sourceTree = "<group>"; };
                72FDB1BF0EA7E21C00B2AC84 /* protocol_job_forward.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = protocol_job_forward.defs; path = launchd/src/protocol_job_forward.defs; sourceTree = "<group>"; };
                FC3627DF0E9344BF0054F1A3 /* protocol_vproc.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = protocol_vproc.defs; path = launchd/src/protocol_vproc.defs; sourceTree = "<group>"; };
                FC3628070E9345E10054F1A3 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
                FC36283E0E93463C0054F1A3 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
                72FDB15D0EA7D7B200B2AC84 /* launchd_ktrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd_ktrace.c; path = launchd/src/launchd_ktrace.c; sourceTree = "<group>"; };
                72FDB15E0EA7D7B200B2AC84 /* launchd_ktrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd_ktrace.h; path = launchd/src/launchd_ktrace.h; sourceTree = "<group>"; };
                72FDB1BF0EA7E21C00B2AC84 /* protocol_job_forward.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = protocol_job_forward.defs; path = launchd/src/protocol_job_forward.defs; sourceTree = "<group>"; };
                FC3627DF0E9344BF0054F1A3 /* protocol_vproc.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = protocol_vproc.defs; path = launchd/src/protocol_vproc.defs; sourceTree = "<group>"; };
                FC3628070E9345E10054F1A3 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
                FC36283E0E93463C0054F1A3 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
-               FC36290C0E93475F0054F1A3 /* notify.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = notify.defs; path = /usr/include/mach/notify.defs; sourceTree = "<absolute>"; };
+               FC36290C0E93475F0054F1A3 /* notify.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 4; name = notify.defs; path = /usr/include/mach/notify.defs; sourceTree = SDKROOT; };
                FC3629160E9348390054F1A3 /* protocol_job_reply.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = protocol_job_reply.defs; path = launchd/src/protocol_job_reply.defs; sourceTree = "<group>"; };
                FC3629160E9348390054F1A3 /* protocol_job_reply.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = protocol_job_reply.defs; path = launchd/src/protocol_job_reply.defs; sourceTree = "<group>"; };
-               FC36291F0E9349410054F1A3 /* mach_exc.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = mach_exc.defs; path = /usr/include/mach/mach_exc.defs; sourceTree = "<absolute>"; };
+               FC36291F0E9349410054F1A3 /* mach_exc.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 4; name = mach_exc.defs; path = /usr/include/mach/mach_exc.defs; sourceTree = SDKROOT; };
                FC36292C0E934AA40054F1A3 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = "<absolute>"; };
                FC59A0540E8C884700D41150 /* launchd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = launchd; sourceTree = BUILT_PRODUCTS_DIR; };
                FC36292C0E934AA40054F1A3 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = "<absolute>"; };
                FC59A0540E8C884700D41150 /* launchd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = launchd; sourceTree = BUILT_PRODUCTS_DIR; };
-               FC59A0600E8C885100D41150 /* liblaunch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblaunch.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               FC59A0600E8C885100D41150 /* liblaunch.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = liblaunch.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
                FC59A06D0E8C888A00D41150 /* launchctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = launchctl; sourceTree = BUILT_PRODUCTS_DIR; };
                FC59A0910E8C892300D41150 /* SystemStarter */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SystemStarter; sourceTree = BUILT_PRODUCTS_DIR; };
                FC59A0A40E8C89C100D41150 /* IPC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IPC.h; path = launchd/src/IPC.h; sourceTree = SOURCE_ROOT; };
                FC59A06D0E8C888A00D41150 /* launchctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = launchctl; sourceTree = BUILT_PRODUCTS_DIR; };
                FC59A0910E8C892300D41150 /* SystemStarter */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SystemStarter; sourceTree = BUILT_PRODUCTS_DIR; };
                FC59A0A40E8C89C100D41150 /* IPC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IPC.h; path = launchd/src/IPC.h; sourceTree = SOURCE_ROOT; };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               721FBEBC0EA7AE2F0057462B /* Security.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+               4B0A3102131F24B3002DE2E5 /* XPC */ = {
+                       isa = PBXGroup;
+                       children = (
+                               4B0A3100131F24AC002DE2E5 /* types.defs */,
+                               4B0FB8E91241FE3F00383109 /* domain.defs */,
+                               4B0A30FF131F24AC002DE2E5 /* events.defs */,
+                               4BA2F5FC1243063D00C2AADD /* init.defs */,
+                       );
+                       name = XPC;
+                       sourceTree = "<group>";
+               };
+               4B8D8239132C5F400081FD4E /* Mach */ = {
+                       isa = PBXGroup;
+                       children = (
+                               FC36291F0E9349410054F1A3 /* mach_exc.defs */,
+                               FC36290C0E93475F0054F1A3 /* notify.defs */,
+                       );
+                       name = Mach;
+                       sourceTree = "<group>";
+               };
                4B9EDCD60EAFD11000A78496 /* MIG */ = {
                        isa = PBXGroup;
                        children = (
                4B9EDCD60EAFD11000A78496 /* MIG */ = {
                        isa = PBXGroup;
                        children = (
                                FC3629160E9348390054F1A3 /* protocol_job_reply.defs */,
                                FC3627DF0E9344BF0054F1A3 /* protocol_vproc.defs */,
                                FC59A0BD0E8C8A2A00D41150 /* launchd_internal.defs */,
                                FC3629160E9348390054F1A3 /* protocol_job_reply.defs */,
                                FC3627DF0E9344BF0054F1A3 /* protocol_vproc.defs */,
                                FC59A0BD0E8C8A2A00D41150 /* launchd_internal.defs */,
-                               FC36291F0E9349410054F1A3 /* mach_exc.defs */,
-                               FC36290C0E93475F0054F1A3 /* notify.defs */,
+                               4B287732111A509400C07B35 /* launchd_helper.defs */,
                        );
                        name = MIG;
                        sourceTree = "<group>";
                        );
                        name = MIG;
                        sourceTree = "<group>";
                        isa = PBXGroup;
                        children = (
                                4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */,
                        isa = PBXGroup;
                        children = (
                                4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */,
-                               721FBEBB0EA7AE2F0057462B /* Security.framework */,
                                FC36292C0E934AA40054F1A3 /* libbsm.dylib */,
                                7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */,
                                FCD713730E95DE49001B0111 /* libedit.dylib */,
                                FC36292C0E934AA40054F1A3 /* libbsm.dylib */,
                                7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */,
                                FCD713730E95DE49001B0111 /* libedit.dylib */,
                FC59A04E0E8C883300D41150 /* launchd */ = {
                        isa = PBXGroup;
                        children = (
                FC59A04E0E8C883300D41150 /* launchd */ = {
                        isa = PBXGroup;
                        children = (
+                               4B8D8239132C5F400081FD4E /* Mach */,
+                               4B0A3102131F24B3002DE2E5 /* XPC */,
                                4B9EDCD60EAFD11000A78496 /* MIG */,
                                4B9EDCD70EAFD14500A78496 /* Source */,
                                4B9EDCD90EAFD19800A78496 /* rc */,
                                4B9EDCD60EAFD11000A78496 /* MIG */,
                                4B9EDCD70EAFD14500A78496 /* Source */,
                                4B9EDCD90EAFD19800A78496 /* rc */,
                FC59A0550E8C884700D41150 /* Products */ = {
                        isa = PBXGroup;
                        children = (
                FC59A0550E8C884700D41150 /* Products */ = {
                        isa = PBXGroup;
                        children = (
-                               FC59A0600E8C885100D41150 /* liblaunch.a */,
+                               FC59A0600E8C885100D41150 /* liblaunch.dylib */,
                                FC59A0540E8C884700D41150 /* launchd */,
                                FC59A06D0E8C888A00D41150 /* launchctl */,
                                FC59A0910E8C892300D41150 /* SystemStarter */,
                                FC59A0540E8C884700D41150 /* launchd */,
                                FC59A06D0E8C888A00D41150 /* launchctl */,
                                FC59A0910E8C892300D41150 /* SystemStarter */,
                        );
                        name = liblaunch;
                        productName = launchd_libs;
                        );
                        name = liblaunch;
                        productName = launchd_libs;
-                       productReference = FC59A0600E8C885100D41150 /* liblaunch.a */;
-                       productType = "com.apple.product-type.library.static";
+                       productReference = FC59A0600E8C885100D41150 /* liblaunch.dylib */;
+                       productType = "com.apple.product-type.library.dynamic";
                };
                FC59A06C0E8C888A00D41150 /* launchctl */ = {
                        isa = PBXNativeTarget;
                };
                FC59A06C0E8C888A00D41150 /* launchctl */ = {
                        isa = PBXNativeTarget;
 /* Begin PBXProject section */
                FC59A03F0E8C87FD00D41150 /* Project object */ = {
                        isa = PBXProject;
 /* Begin PBXProject section */
                FC59A03F0E8C87FD00D41150 /* Project object */ = {
                        isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 0420;
+                       };
                        buildConfigurationList = FC59A0420E8C87FD00D41150 /* Build configuration list for PBXProject "launchd" */;
                        buildConfigurationList = FC59A0420E8C87FD00D41150 /* Build configuration list for PBXProject "launchd" */;
-                       compatibilityVersion = "Xcode 2.4";
+                       compatibilityVersion = "Xcode 3.2";
+                       developmentRegion = English;
                        hasScannedForEncodings = 0;
                        hasScannedForEncodings = 0;
+                       knownRegions = (
+                               English,
+                               Japanese,
+                               French,
+                               German,
+                       );
                        mainGroup = FC59A03D0E8C87FD00D41150;
                        productRefGroup = FC59A0550E8C884700D41150 /* Products */;
                        projectDirPath = "";
                        mainGroup = FC59A03D0E8C87FD00D41150;
                        productRefGroup = FC59A0550E8C884700D41150 /* Products */;
                        projectDirPath = "";
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               4B9A1C1F132759F700019C67 /* events.defs in Sources */,
+                               4BF8727C1187A5F000CC7DB5 /* launchd_helper.defs in Sources */,
                                4B10F1B90F43BE7E00875782 /* launchd_internal.defs in Sources */,
                                4B10F1BA0F43BE7E00875782 /* protocol_vproc.defs in Sources */,
                                4B10F1BB0F43BE7E00875782 /* protocol_job_reply.defs in Sources */,
                                4B10F1B90F43BE7E00875782 /* launchd_internal.defs in Sources */,
                                4B10F1BA0F43BE7E00875782 /* protocol_vproc.defs in Sources */,
                                4B10F1BB0F43BE7E00875782 /* protocol_job_reply.defs in Sources */,
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               4B28781B111A61A400C07B35 /* launchd_helper.defs in Sources */,
                                FC59A0BF0E8C8A2A00D41150 /* launchd_internal.defs in Sources */,
                                FC3627E10E9344BF0054F1A3 /* protocol_vproc.defs in Sources */,
                                FC3629170E9348390054F1A3 /* protocol_job_reply.defs in Sources */,
                                726055EC0EA7EC2400D65FE7 /* mach_exc.defs in Sources */,
                                FC36290D0E93475F0054F1A3 /* notify.defs in Sources */,
                                FC59A0BF0E8C8A2A00D41150 /* launchd_internal.defs in Sources */,
                                FC3627E10E9344BF0054F1A3 /* protocol_vproc.defs in Sources */,
                                FC3629170E9348390054F1A3 /* protocol_job_reply.defs in Sources */,
                                726055EC0EA7EC2400D65FE7 /* mach_exc.defs in Sources */,
                                FC36290D0E93475F0054F1A3 /* notify.defs in Sources */,
+                               4B0FB8EA1241FE3F00383109 /* domain.defs in Sources */,
+                               4B0A3103131F266E002DE2E5 /* events.defs in Sources */,
+                               4BA2F5FD1243063D00C2AADD /* init.defs in Sources */,
+                               72FDB1C00EA7E21C00B2AC84 /* protocol_job_forward.defs in Sources */,
                                FC59A0C50E8C8A4700D41150 /* launchd.c in Sources */,
                                FC59A0BA0E8C8A1F00D41150 /* launchd_runtime.c in Sources */,
                                FC59A0B90E8C8A1F00D41150 /* launchd_runtime_kill.c in Sources */,
                                FC59A0BB0E8C8A1F00D41150 /* launchd_core_logic.c in Sources */,
                                FC59A0B80E8C8A1F00D41150 /* launchd_unix_ipc.c in Sources */,
                                72FDB15F0EA7D7B200B2AC84 /* launchd_ktrace.c in Sources */,
                                FC59A0C50E8C8A4700D41150 /* launchd.c in Sources */,
                                FC59A0BA0E8C8A1F00D41150 /* launchd_runtime.c in Sources */,
                                FC59A0B90E8C8A1F00D41150 /* launchd_runtime_kill.c in Sources */,
                                FC59A0BB0E8C8A1F00D41150 /* launchd_core_logic.c in Sources */,
                                FC59A0B80E8C8A1F00D41150 /* launchd_unix_ipc.c in Sources */,
                                72FDB15F0EA7D7B200B2AC84 /* launchd_ktrace.c in Sources */,
-                               72FDB1C00EA7E21C00B2AC84 /* protocol_job_forward.defs in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                FC59A0F70E8C8AA600D41150 /* libbootstrap.c in Sources */,
                                FC3627E00E9344BF0054F1A3 /* protocol_vproc.defs in Sources */,
                                726056090EA7FCF200D65FE7 /* launchd_ktrace.c in Sources */,
                                FC59A0F70E8C8AA600D41150 /* libbootstrap.c in Sources */,
                                FC3627E00E9344BF0054F1A3 /* protocol_vproc.defs in Sources */,
                                726056090EA7FCF200D65FE7 /* launchd_ktrace.c in Sources */,
+                               4B287733111A509400C07B35 /* launchd_helper.defs in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                4B10F1D20F43BE7E00875782 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                4B10F1D20F43BE7E00875782 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               COPY_PHASE_STRIP = YES;
-                               DEAD_CODE_STRIPPING = NO;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       __LAUNCH_DISABLE_XPC_SUPPORT__,
+                                       XPC_BUILDING_LAUNCHD,
+                               );
+                               HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/local/include";
                                INSTALL_PATH = /sbin;
                                INSTALL_PATH = /sbin;
-                               PREBINDING = NO;
+                               OTHER_MIGFLAGS = "-DXPC_BUILDING_LAUNCHD -I$(PROJECT_DIR)/launchd/src/ -I$(SDKROOT)/usr/local/include";
                                PRODUCT_NAME = launchd;
                                PRODUCT_NAME = launchd;
-                               STRIP_STYLE = debugging;
-                               VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
-                               ZERO_LINK = NO;
                        };
                        name = Release;
                };
                4B10F1F20F43BF5C00875782 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        };
                        name = Release;
                };
                4B10F1F20F43BF5C00875782 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386";
-                               COPY_PHASE_STRIP = YES;
-                               DEAD_CODE_STRIPPING = NO;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                INSTALL_PATH = /bin;
                                INSTALL_PATH = /bin;
-                               PREBINDING = NO;
                                PRODUCT_NAME = launchctl;
                                PRODUCT_NAME = launchctl;
-                               STRIP_STYLE = debugging;
-                               VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
-                               ZERO_LINK = NO;
                        };
                        name = Release;
                };
                        };
                        name = Release;
                };
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                PRODUCT_NAME = embedded;
                                ZERO_LINK = NO;
                        };
                                PRODUCT_NAME = embedded;
                                ZERO_LINK = NO;
                        };
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
+                               CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                DEAD_CODE_STRIPPING = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_MODEL_TUNING = "";
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
                                GCC_MODEL_TUNING = "";
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
                                        "-Dmig_external=__private_extern__",
                                        "-D_DARWIN_USE_64_BIT_INODE=1",
                                );
                                        "-Dmig_external=__private_extern__",
                                        "-D_DARWIN_USE_64_BIT_INODE=1",
                                );
+                               STRIP_STYLE = all;
+                               VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = (
                                        "-Wall",
                                        "-Wextra",
                                        "-Waggregate-return",
                                        "-Wmissing-declarations",
                                );
                                WARNING_CFLAGS = (
                                        "-Wall",
                                        "-Wextra",
                                        "-Waggregate-return",
                                        "-Wmissing-declarations",
                                );
+                               ZERO_LINK = NO;
                        };
                        name = Release;
                };
                FC59A0580E8C884800D41150 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        };
                        name = Release;
                };
                FC59A0580E8C884800D41150 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               COPY_PHASE_STRIP = YES;
-                               DEAD_CODE_STRIPPING = NO;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               ALWAYS_SEARCH_USER_PATHS = YES;
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = "";
+                               HEADER_SEARCH_PATHS = "";
                                INSTALL_PATH = /sbin;
                                INSTALL_PATH = /sbin;
-                               PREBINDING = NO;
+                               OTHER_CFLAGS = (
+                                       "-D__MigTypeCheck=1",
+                                       "-Dmig_external=__private_extern__",
+                                       "-D_DARWIN_USE_64_BIT_INODE=1",
+                               );
+                               OTHER_MIGFLAGS = "-DXPC_BUILDING_LAUNCHD -I$(PROJECT_DIR)/launchd/src/";
                                PRODUCT_NAME = launchd;
                                PRODUCT_NAME = launchd;
-                               STRIP_STYLE = debugging;
-                               VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
-                               ZERO_LINK = NO;
                        };
                        name = Release;
                };
                FC59A0620E8C885100D41150 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        };
                        name = Release;
                };
                FC59A0620E8C885100D41150 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = "$(NATIVE_ARCH_ACTUAL)";
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
                                BUILD_VARIANTS = (
                                        normal,
                                        debug,
                                        profile,
                                );
                                BUILD_VARIANTS = (
                                        normal,
                                        debug,
                                        profile,
                                );
-                               COPY_PHASE_STRIP = YES;
-                               CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               CRASHREPORTER_LINKER_FLAGS = "";
+                               "CRASHREPORTER_LINKER_FLAGS[sdk=macosx*][arch=*]" = "-lCrashReporterClient";
+                               "CRASHREPORTER_LINKER_FLAGS[sdk=macosx10.6][arch=*]" = "";
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
+                               EXECUTABLE_PREFIX = lib;
                                INSTALLHDRS_SCRIPT_PHASE = YES;
                                INSTALLHDRS_SCRIPT_PHASE = YES;
-                               INSTALL_PATH = /usr/local/lib/system;
+                               INSTALL_PATH = /usr/lib/system;
+                               LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
                                OTHER_CFLAGS = (
                                        "-D__MigTypeCheck=1",
                                        "-Dmig_external=__private_extern__",
                                        "-D__DARWIN_NON_CANCELABLE=1",
                                        "-D_DARWIN_USE_64_BIT_INODE=1",
                                );
                                OTHER_CFLAGS = (
                                        "-D__MigTypeCheck=1",
                                        "-Dmig_external=__private_extern__",
                                        "-D__DARWIN_NON_CANCELABLE=1",
                                        "-D_DARWIN_USE_64_BIT_INODE=1",
                                );
+                               OTHER_LDFLAGS = (
+                                       "-Wl,-umbrella,System",
+                                       "$(CRASHREPORTER_LINKER_FLAGS)",
+                               );
                                PRODUCT_NAME = launch;
                                PUBLIC_HEADERS_FOLDER_PATH = /usr/include;
                                PRODUCT_NAME = launch;
                                PUBLIC_HEADERS_FOLDER_PATH = /usr/include;
-                               VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
-                               VERSIONING_SYSTEM = "apple-generic";
-                               VERSION_INFO_PREFIX = __;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               STRIP_STYLE = "non-global";
+                               VERSION_INFO_PREFIX = _;
                        };
                        name = Release;
                };
                FC59A0700E8C888A00D41150 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        };
                        name = Release;
                };
                FC59A0700E8C888A00D41150 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386";
-                               COPY_PHASE_STRIP = YES;
-                               DEAD_CODE_STRIPPING = NO;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_PATH = /bin;
                                INSTALL_PATH = /bin;
-                               PREBINDING = NO;
                                PRODUCT_NAME = launchctl;
                                PRODUCT_NAME = launchctl;
-                               STRIP_STYLE = debugging;
-                               VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
-                               ZERO_LINK = NO;
                        };
                        name = Release;
                };
                        };
                        name = Release;
                };
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                PRODUCT_NAME = default;
                                ZERO_LINK = NO;
                        };
                                PRODUCT_NAME = default;
                                ZERO_LINK = NO;
                        };
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                PRODUCT_NAME = launchd_libs;
                                ZERO_LINK = NO;
                        };
                                PRODUCT_NAME = launchd_libs;
                                ZERO_LINK = NO;
                        };
                FC59A0940E8C892400D41150 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                FC59A0940E8C892400D41150 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386";
-                               COPY_PHASE_STRIP = YES;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_PATH = /sbin;
                                INSTALL_PATH = /sbin;
-                               PREBINDING = NO;
                                PRODUCT_NAME = SystemStarter;
                                PRODUCT_NAME = SystemStarter;
-                               STRIP_STYLE = debugging;
-                               VALID_ARCHS = "i386 ppc ppc64 ppc7400 ppc970 x86_64";
-                               ZERO_LINK = NO;
+                               VALID_ARCHS = "i386 x86_64";
                        };
                        name = Release;
                };
                FC59A0D10E8C8A5C00D41150 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        };
                        name = Release;
                };
                FC59A0D10E8C8A5C00D41150 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386";
-                               COPY_PHASE_STRIP = YES;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_PATH = /usr/libexec;
                                INSTALL_PATH = /usr/libexec;
-                               PREBINDING = NO;
                                PRODUCT_NAME = launchproxy;
                                PRODUCT_NAME = launchproxy;
-                               STRIP_STYLE = debugging;
-                               VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
-                               ZERO_LINK = NO;
                        };
                        name = Release;
                };
                FCD7132E0E95D64E001B0111 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        };
                        name = Release;
                };
                FCD7132E0E95D64E001B0111 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386";
-                               COPY_PHASE_STRIP = YES;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_PATH = /bin;
                                INSTALL_PATH = /bin;
-                               PREBINDING = NO;
                                PRODUCT_NAME = wait4path;
                                PRODUCT_NAME = wait4path;
-                               STRIP_STYLE = debugging;
-                               VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
-                               ZERO_LINK = NO;
                        };
                        name = Release;
                };
                        };
                        name = Release;
                };
index d85a4828ce3864cf4cddb316969565b95afc1f9e..b28226c4aaa2d2faad66d8f49cbdbc9c7521f375 100644 (file)
@@ -35,4 +35,4 @@
  **/
 void MonitorStartupItem (StartupContext aStartupContext, CFMutableDictionaryRef anItem);
 
  **/
 void MonitorStartupItem (StartupContext aStartupContext, CFMutableDictionaryRef anItem);
 
-#endif /* _IPC_H_ */
+#endif
index 18677b1bcb6c6d1ea0442c813bedf405066f6bd8..9fc2325a6e1f7191c88a9d8283e6ce653558eb3a 100644 (file)
@@ -183,7 +183,6 @@ static void SpecialCasesStartupItemHandler(CFMutableDictionaryRef aConfig)
                                        break;
                        }
                        if (*c == NULL) {
                                        break;
                        }
                        if (*c == NULL) {
-                               CFRetain(ci);
                                CFArrayAppendValue(aNewList, ci);
                                CF_syslog(LOG_DEBUG, CFSTR("%@: Keeping %@"), type, ci);
                        }
                                CFArrayAppendValue(aNewList, ci);
                                CF_syslog(LOG_DEBUG, CFSTR("%@: Keeping %@"), type, ci);
                        }
@@ -441,7 +440,7 @@ CFMutableDictionaryRef StartupItemListGetProvider(CFArrayRef anItemList, CFStrin
        return aResult;
 }
 
        return aResult;
 }
 
-CFArrayRef StartupItemListGetRunning(CFArrayRef anItemList)
+CFArrayRef StartupItemListCreateFromRunning(CFArrayRef anItemList)
 {
        CFMutableArrayRef aResult = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
        if (aResult) {
 {
        CFMutableArrayRef aResult = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
        if (aResult) {
@@ -837,7 +836,7 @@ CFMutableDictionaryRef StartupItemListGetNext(CFArrayRef aWaitingList, CFDiction
        return aNextItem;
 }
 
        return aNextItem;
 }
 
-CFStringRef StartupItemGetDescription(CFMutableDictionaryRef anItem)
+CFStringRef StartupItemCreateDescription(CFMutableDictionaryRef anItem)
 {
        CFStringRef aString = NULL;
 
 {
        CFStringRef aString = NULL;
 
index d367340f60a750881643da48b1b61a79e388ff22..5cf6c086a0846435f3249d5fe35ca4ab1cb131bc 100644 (file)
@@ -81,12 +81,12 @@ CFMutableDictionaryRef StartupItemListGetNext (CFArrayRef      aWaitingList,
 CFMutableDictionaryRef StartupItemWithPID (CFArrayRef anItemList, pid_t aPID);
 pid_t StartupItemGetPID(CFDictionaryRef anItem);
 
 CFMutableDictionaryRef StartupItemWithPID (CFArrayRef anItemList, pid_t aPID);
 pid_t StartupItemGetPID(CFDictionaryRef anItem);
 
-CFStringRef StartupItemGetDescription(CFMutableDictionaryRef anItem);
+CFStringRef StartupItemCreateDescription(CFMutableDictionaryRef anItem);
 
 /*
  * Returns a list of currently executing startup items.
  */
 
 /*
  * Returns a list of currently executing startup items.
  */
-CFArrayRef StartupItemListGetRunning(CFArrayRef anItemList);
+CFArrayRef StartupItemListCreateFromRunning(CFArrayRef anItemList);
 
 /*
  * Returns the total number of "Provides" entries of all loaded items.
 
 /*
  * Returns the total number of "Provides" entries of all loaded items.
@@ -112,4 +112,4 @@ void StartupItemSetStatus(CFMutableDictionaryRef aStatusDict, CFMutableDictionar
  */
 bool StartupItemSecurityCheck(const char *aPath);
 
  */
 bool StartupItemSecurityCheck(const char *aPath);
 
-#endif /* _StartupItems_H_ */
+#endif
index fb93db79307c57f54a8bb2b17b56ded4238c7f7c..02663f8da6ab462c8f16c1fcb96442ee48dd7b30 100644 (file)
@@ -191,10 +191,10 @@ checkForActivity(StartupContext aStartupContext)
                        aWaitingForString = CFSTR("Waiting for %@");
                }
                if (aLastStatusDictionaryCount == aCount) {
                        aWaitingForString = CFSTR("Waiting for %@");
                }
                if (aLastStatusDictionaryCount == aCount) {
-                       CFArrayRef      aRunningList = StartupItemListGetRunning(aStartupContext->aWaitingList);
+                       CFArrayRef aRunningList = StartupItemListCreateFromRunning(aStartupContext->aWaitingList);
                        if (aRunningList && CFArrayGetCount(aRunningList) > 0) {
                                CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aRunningList, 0);
                        if (aRunningList && CFArrayGetCount(aRunningList) > 0) {
                                CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aRunningList, 0);
-                               CFStringRef     anItemDescription = StartupItemGetDescription(anItem);
+                               CFStringRef     anItemDescription = StartupItemCreateDescription(anItem);
                                CFStringRef     aString = aWaitingForString && anItemDescription ?
                                CFStringCreateWithFormat(NULL, NULL, aWaitingForString, anItemDescription) : NULL;
 
                                CFStringRef     aString = aWaitingForString && anItemDescription ?
                                CFStringCreateWithFormat(NULL, NULL, aWaitingForString, anItemDescription) : NULL;
 
@@ -377,7 +377,7 @@ CF_syslog(int level, CFStringRef message,...)
        va_end(ap);
 
        if (CFStringGetCString(cooked_msg, buf, sizeof(buf), kCFStringEncodingUTF8))
        va_end(ap);
 
        if (CFStringGetCString(cooked_msg, buf, sizeof(buf), kCFStringEncodingUTF8))
-               syslog(level, buf);
+               syslog(level, "%s", buf);
 
        CFRelease(cooked_msg);
 }
 
        CFRelease(cooked_msg);
 }
index 6a6c0ab0997b36a224802b54616bc18c2e51934d..417d30767247a161becc43826f290ef04a02f7a2 100644 (file)
@@ -48,4 +48,4 @@ typedef enum {
 void CF_syslog(int level, CFStringRef message, ...);
 extern bool gVerboseFlag;
 
 void CF_syslog(int level, CFStringRef message, ...);
 extern bool gVerboseFlag;
 
-#endif /* _SYSTEM_STARTER_H_ */
+#endif
index 3a94095f205b3cb47f2740db721ed00516c0ac99..9dc00238b4034e07b88a0cea354a01c38e6eab6c 100644 (file)
@@ -85,4 +85,4 @@ typedef struct SystemStarterIPCMessage {
 #define kIPCConfigSettingVerboseFlag   CFSTR("VerboseFlag")
 #define kIPCConfigSettingNetworkUp     CFSTR("NetworkUp")
 
 #define kIPCConfigSettingVerboseFlag   CFSTR("VerboseFlag")
 #define kIPCConfigSettingNetworkUp     CFSTR("NetworkUp")
 
-#endif /* _SYSTEM_STARTER_IPC_H */
+#endif
index 15f32481310c9f392e86a799a087c0a435c0ed8a..f09f82f2db35079e472f7e0ac130d27d2fa40968 100644 (file)
@@ -293,9 +293,9 @@ bootstrap_create_service(mach_port_t bp, name_t service_name, mach_port_t *sp);
  * bootstrap_check_in()
  *
  * Returns the receive right for the service named by service_name. The
  * bootstrap_check_in()
  *
  * Returns the receive right for the service named by service_name. The
- * service must have previously been declared in this bootstrap context via
- * a call to bootstrap_create_service().  Attempts to check_in a service
- * which is already active are not allowed.
+ * service must have been declared in the launchd.plist(5) file associated 
+ * with the job.  Attempts to check_in a service which is already active 
+ * are not allowed.
  *
  * If the service was declared as being associated with a server, the
  * check_in must come from the server's privileged port (server_port).
  *
  * If the service was declared as being associated with a server, the
  * check_in must come from the server's privileged port (server_port).
index 121e9e917e4a9c522c3208cccc06965bf35400f0..54d443e59cda96a806e442914a4404a273424e08 100644 (file)
 
 #include <servers/bootstrap.h>
 #include <sys/types.h>
 
 #include <servers/bootstrap.h>
 #include <sys/types.h>
+#include <uuid/uuid.h>
 
 __BEGIN_DECLS
 
 #pragma GCC visibility push(default)
 
 
 __BEGIN_DECLS
 
 #pragma GCC visibility push(default)
 
-#define BOOTSTRAP_PER_PID_SERVICE                      1 << 0
-#define BOOTSTRAP_ALLOW_LOOKUP                         1 << 1
-#define BOOTSTRAP_DENY_JOB_CREATION                    1 << 2
-#define BOOTSTRAP_PRIVILEGED_SERVER                    1 << 3
-#define BOOTSTRAP_FORCE_LOCAL                          1 << 4
+#define BOOTSTRAP_PER_PID_SERVICE                      (1 << 0)
+#define BOOTSTRAP_ALLOW_LOOKUP                         (1 << 1)
+#define BOOTSTRAP_DENY_JOB_CREATION                    (1 << 2)
+#define BOOTSTRAP_PRIVILEGED_SERVER                    (1 << 3)
+#define BOOTSTRAP_FORCE_LOCAL                          (1 << 4)
+#define BOOTSTRAP_SPECIFIC_INSTANCE                    (1 << 5)
+#define BOOTSTRAP_STRICT_CHECKIN                       (1 << 6)
+#define BOOTSTRAP_STRICT_LOOKUP                                (1 << 7)
 
 
-#define BOOTSTRAP_PROPERTY_EXPLICITSUBSET      1 << 0 /* Created via bootstrap_subset(). */
-#define BOOTSTRAP_PROPERTY_IMPLICITSUBSET      1 << 1 /* Created via _vprocmgr_switch_to_session(). */
-#define BOOTSTRAP_PROPERTY_MOVEDSUBSET         1 << 2 /* Created via _vprocmgr_move_subset_to_user(). */
-#define BOOTSTRAP_PROPERTY_PERUSER                     1 << 3 /* A per-user launchd's root bootstrap. */
+#define BOOTSTRAP_PROPERTY_EXPLICITSUBSET      (1 << 0) /* Created via bootstrap_subset(). */
+#define BOOTSTRAP_PROPERTY_IMPLICITSUBSET      (1 << 1) /* Created via _vprocmgr_switch_to_session(). */
+#define BOOTSTRAP_PROPERTY_MOVEDSUBSET         (1 << 2) /* Created via _vprocmgr_move_subset_to_user(). */
+#define BOOTSTRAP_PROPERTY_PERUSER                     (1 << 3) /* A per-user launchd's root bootstrap. */
+#define BOOTSTRAP_PROPERTY_XPC_DOMAIN          (1 << 4) /* An XPC domain. Duh. */
+#define BOOTSTRAP_PROPERTY_XPC_SINGLETON       (1 << 5) /* A singleton XPC domain. */
+
+void bootstrap_init(void);
 
 kern_return_t bootstrap_register2(mach_port_t bp, name_t service_name, mach_port_t sp, uint64_t flags);
 
 
 kern_return_t bootstrap_register2(mach_port_t bp, name_t service_name, mach_port_t sp, uint64_t flags);
 
@@ -48,6 +56,12 @@ kern_return_t bootstrap_look_up_per_user(mach_port_t bp, const name_t service_na
 
 kern_return_t bootstrap_lookup_children(mach_port_t bp, mach_port_array_t *children, name_array_t *names, bootstrap_property_array_t *properties, mach_msg_type_number_t *n_children);
 
 
 kern_return_t bootstrap_lookup_children(mach_port_t bp, mach_port_array_t *children, name_array_t *names, bootstrap_property_array_t *properties, mach_msg_type_number_t *n_children);
 
+kern_return_t bootstrap_look_up3(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, const uuid_t instance_id, uint64_t flags);
+
+kern_return_t bootstrap_check_in3(mach_port_t bp, const name_t service_name, mach_port_t *sp, uuid_t instance_id, uint64_t flags);
+
+kern_return_t bootstrap_get_root(mach_port_t bp, mach_port_t *root);
+
 #pragma GCC visibility pop
 
 __END_DECLS
 #pragma GCC visibility pop
 
 __END_DECLS
index ffac1a33962dd3a103349c425cfc5e5c11b18ca7..8ab51c780edb6fe1db6c2a05642f242c408c52a0 100644 (file)
@@ -1,11 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
 <plist version="1.0">
 <dict>
-       <key>Label</key>
-       <string>com.apple.SystemStarter</string>
-       <key>Program</key>
-       <string>/sbin/SystemStarter</string>
        <key>KeepAlive</key>
        <dict>
                <key>PathState</key>
        <key>KeepAlive</key>
        <dict>
                <key>PathState</key>
                        <true/>
                </dict>
        </dict>
                        <true/>
                </dict>
        </dict>
+       <key>Label</key>
+       <string>com.apple.SystemStarter</string>
+       <key>Program</key>
+       <string>/sbin/SystemStarter</string>
        <key>QueueDirectories</key>
        <array>
                <string>/Library/StartupItems</string>
                <string>/System/Library/StartupItems</string>
        </array>
        <key>QueueDirectories</key>
        <array>
                <string>/Library/StartupItems</string>
                <string>/System/Library/StartupItems</string>
        </array>
-       <key>HopefullyExitsFirst</key>
-       <true/>
 </dict>
 </plist>
 </dict>
 </plist>
index 23b1706dd4c37fbda635062fb5677db754d98b5f..9f46ab6f317cc85c2bbf9854b02cfa53f0e8bae8 100644 (file)
@@ -3,6 +3,5 @@
 #include <TargetConfig.h>
 #define HAVE_QUARANTINE TARGET_HAVE_QUARANTINE
 #define HAVE_SANDBOX TARGET_HAVE_SANDBOX
 #include <TargetConfig.h>
 #define HAVE_QUARANTINE TARGET_HAVE_QUARANTINE
 #define HAVE_SANDBOX TARGET_HAVE_SANDBOX
-#define HAVE_SECURITY !TARGET_HAVE_EMBEDDED_SECURITY
 #define HAVE_LIBAUDITD !TARGET_OS_EMBEDDED
 #define HAVE_LIBAUDITD !TARGET_OS_EMBEDDED
-#endif /* __CONFIG_H__ */
+#endif
index d8ed3028c545ac4d9a3138de82392b61a4d949c8..61bf323389317b78204368060eead76baf255c8d 100644 (file)
@@ -71,6 +71,8 @@ __BEGIN_DECLS
 #define LAUNCH_JOBKEY_LIMITLOADTOHOSTS                         "LimitLoadToHosts"
 #define LAUNCH_JOBKEY_LIMITLOADFROMHOSTS                       "LimitLoadFromHosts"
 #define LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE           "LimitLoadToSessionType"
 #define LAUNCH_JOBKEY_LIMITLOADTOHOSTS                         "LimitLoadToHosts"
 #define LAUNCH_JOBKEY_LIMITLOADFROMHOSTS                       "LimitLoadFromHosts"
 #define LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE           "LimitLoadToSessionType"
+#define LAUNCH_JOBKEY_LIMITLOADTOHARDWARE                      "LimitLoadToHardware"
+#define LAUNCH_JOBKEY_LIMITLOADFROMHARDWARE                    "LimitLoadFromHardware"
 #define LAUNCH_JOBKEY_RUNATLOAD                                                "RunAtLoad"
 #define LAUNCH_JOBKEY_ROOTDIRECTORY                                    "RootDirectory"
 #define LAUNCH_JOBKEY_WORKINGDIRECTORY                         "WorkingDirectory"
 #define LAUNCH_JOBKEY_RUNATLOAD                                                "RunAtLoad"
 #define LAUNCH_JOBKEY_ROOTDIRECTORY                                    "RootDirectory"
 #define LAUNCH_JOBKEY_WORKINGDIRECTORY                         "WorkingDirectory"
@@ -111,6 +113,7 @@ __BEGIN_DECLS
 #define LAUNCH_JOBKEY_MACH_RESETATCLOSE                                "ResetAtClose"
 #define LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN                    "HideUntilCheckIn"
 #define LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH                "DrainMessagesOnCrash"
 #define LAUNCH_JOBKEY_MACH_RESETATCLOSE                                "ResetAtClose"
 #define LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN                    "HideUntilCheckIn"
 #define LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH                "DrainMessagesOnCrash"
+#define LAUNCH_JOBKEY_MACH_PINGEVENTUPDATES                    "PingEventUpdates"
 
 #define LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT         "SuccessfulExit"
 #define LAUNCH_JOBKEY_KEEPALIVE_NETWORKSTATE           "NetworkState"
 
 #define LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT         "SuccessfulExit"
 #define LAUNCH_JOBKEY_KEEPALIVE_NETWORKSTATE           "NetworkState"
@@ -118,6 +121,9 @@ __BEGIN_DECLS
 #define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBACTIVE         "OtherJobActive"
 #define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBENABLED                "OtherJobEnabled"
 #define LAUNCH_JOBKEY_KEEPALIVE_AFTERINITIALDEMAND     "AfterInitialDemand"
 #define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBACTIVE         "OtherJobActive"
 #define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBENABLED                "OtherJobEnabled"
 #define LAUNCH_JOBKEY_KEEPALIVE_AFTERINITIALDEMAND     "AfterInitialDemand"
+#define LAUNCH_JOBKEY_KEEPALIVE_CRASHED                                "Crashed"
+
+#define LAUNCH_JOBKEY_LAUNCHEVENTS                                     "LaunchEvents"
 
 #define LAUNCH_JOBKEY_CAL_MINUTE                                       "Minute"
 #define LAUNCH_JOBKEY_CAL_HOUR                                         "Hour"
 
 #define LAUNCH_JOBKEY_CAL_MINUTE                                       "Minute"
 #define LAUNCH_JOBKEY_CAL_HOUR                                         "Hour"
index c0642f153f296cd68c4d34236c8370c12927165f..46c1725e63d4450d140693a2e65246ae5cdcefb1 100644 (file)
 
 #define LAUNCHD_DB_PREFIX "/var/db/launchd.db"
 
 
 #define LAUNCHD_DB_PREFIX "/var/db/launchd.db"
 
+struct _launch_data {
+       uint64_t type;
+       union {
+               struct {
+                       union {
+                               launch_data_t *_array;
+                               char *string;
+                               void *opaque;
+                               int64_t __junk;
+                       };
+                       union {
+                               uint64_t _array_cnt;
+                               uint64_t string_len;
+                               uint64_t opaque_size;
+                       };
+               };
+               int64_t fd;
+               uint64_t  mp;
+               uint64_t err;
+               int64_t number;
+               uint64_t boolean; /* We'd use 'bool' but this struct needs to be used under Rosetta, and sizeof(bool) is different between PowerPC and Intel */
+               double float_num;
+       };
+};
+
+typedef struct _launch *launch_t;
+
+launch_t launchd_fdopen(int, int);
+int launchd_getfd(launch_t);
+void launchd_close(launch_t, __typeof__(close) closefunc);
+
+launch_data_t launch_data_new_errno(int);
+bool launch_data_set_errno(launch_data_t, int);
+
+int launchd_msg_send(launch_t, launch_data_t);
+int launchd_msg_recv(launch_t, void (*)(launch_data_t, void *), void *);
+
 size_t launch_data_pack(launch_data_t d, void *where, size_t len, int *fd_where, size_t *fdslotsleft);
 launch_data_t launch_data_unpack(void *data, size_t data_size, int *fds, size_t fd_cnt, size_t *data_offset, size_t *fdoffset);
 
 size_t launch_data_pack(launch_data_t d, void *where, size_t len, int *fd_where, size_t *fdslotsleft);
 launch_data_t launch_data_unpack(void *data, size_t data_size, int *fds, size_t fd_cnt, size_t *data_offset, size_t *fdoffset);
 
index e19df70c37ad0d671aeef8c056abf11c8d64886e..1f5c156ca841c16c846a0ea4b0552c36f5659a3e 100644 (file)
@@ -58,12 +58,19 @@ __BEGIN_DECLS
 #define LAUNCH_JOBKEY_JETSAMPRIORITY                                   "JetsamPriority"
 #define LAUNCH_JOBKEY_JETSAMMEMORYLIMIT                                        "JetsamMemoryLimit"
 #define LAUNCH_JOBKEY_SECURITYSESSIONUUID                              "SecuritySessionUUID"
 #define LAUNCH_JOBKEY_JETSAMPRIORITY                                   "JetsamPriority"
 #define LAUNCH_JOBKEY_JETSAMMEMORYLIMIT                                        "JetsamMemoryLimit"
 #define LAUNCH_JOBKEY_SECURITYSESSIONUUID                              "SecuritySessionUUID"
+#define LAUNCH_JOBKEY_DISABLEASLR                                              "DisableASLR"
+#define LAUNCH_JOBKEY_XPCDOMAIN                                                        "XPCDomain"
+#define LAUNCH_JOBKEY_POSIXSPAWNTYPE                                   "POSIXSpawnType"
 
 #define LAUNCH_KEY_JETSAMLABEL                                                 "JetsamLabel"
 #define LAUNCH_KEY_JETSAMFRONTMOST                                             "JetsamFrontmost"
 #define LAUNCH_KEY_JETSAMPRIORITY                                              LAUNCH_JOBKEY_JETSAMPRIORITY
 #define LAUNCH_KEY_JETSAMMEMORYLIMIT                                   LAUNCH_JOBKEY_JETSAMMEMORYLIMIT
 
 
 #define LAUNCH_KEY_JETSAMLABEL                                                 "JetsamLabel"
 #define LAUNCH_KEY_JETSAMFRONTMOST                                             "JetsamFrontmost"
 #define LAUNCH_KEY_JETSAMPRIORITY                                              LAUNCH_JOBKEY_JETSAMPRIORITY
 #define LAUNCH_KEY_JETSAMMEMORYLIMIT                                   LAUNCH_JOBKEY_JETSAMMEMORYLIMIT
 
+#define LAUNCH_KEY_POSIXSPAWNTYPE_TALAPP                               "TALApp"
+#define LAUNCH_KEY_POSIXSPAWNTYPE_WIDGET                               "Widget"
+#define LAUNCH_KEY_POSIXSPAWNTYPE_IOSAPP                               "iOSApp"
+
 #define LAUNCH_JOBKEY_EMBEDDEDPRIVILEGEDISPENSATION            "EmbeddedPrivilegeDispensation"
 #define LAUNCH_JOBKEY_EMBEDDEDMAINTHREADPRIORITY               "EmbeddedMainThreadPriority"
 
 #define LAUNCH_JOBKEY_EMBEDDEDPRIVILEGEDISPENSATION            "EmbeddedPrivilegeDispensation"
 #define LAUNCH_JOBKEY_EMBEDDEDMAINTHREADPRIORITY               "EmbeddedMainThreadPriority"
 
@@ -72,6 +79,10 @@ __BEGIN_DECLS
 #define LAUNCH_JOBKEY_SERVICEIPC                                               "ServiceIPC"
 #define LAUNCH_JOBKEY_BINARYORDERPREFERENCE                            "BinaryOrderPreference"
 #define LAUNCH_JOBKEY_MACHEXCEPTIONHANDLER                             "MachExceptionHandler"
 #define LAUNCH_JOBKEY_SERVICEIPC                                               "ServiceIPC"
 #define LAUNCH_JOBKEY_BINARYORDERPREFERENCE                            "BinaryOrderPreference"
 #define LAUNCH_JOBKEY_MACHEXCEPTIONHANDLER                             "MachExceptionHandler"
+#define LAUNCH_JOBKEY_MULTIPLEINSTANCES                                        "MultipleInstances"
+#define LAUNCH_JOBKEY_EVENTMONITOR                                             "EventMonitor"
+#define LAUNCH_JOBKEY_SHUTDOWNMONITOR                                  "ShutdownMonitor"
+#define LAUNCH_JOBKEY_BEGINTRANSACTIONATSHUTDOWN               "BeginTransactionAtShutdown"
 
 #define LAUNCH_JOBKEY_MACH_KUNCSERVER                                  "kUNCServer"
 #define LAUNCH_JOBKEY_MACH_EXCEPTIONSERVER                             "ExceptionServer"
 
 #define LAUNCH_JOBKEY_MACH_KUNCSERVER                                  "kUNCServer"
 #define LAUNCH_JOBKEY_MACH_EXCEPTIONSERVER                             "ExceptionServer"
@@ -79,17 +90,7 @@ __BEGIN_DECLS
 #define LAUNCH_JOBKEY_MACH_HOSTSPECIALPORT                             "HostSpecialPort"
 #define LAUNCH_JOBKEY_MACH_ENTERKERNELDEBUGGERONCLOSE  "EnterKernelDebuggerOnClose"
 
 #define LAUNCH_JOBKEY_MACH_HOSTSPECIALPORT                             "HostSpecialPort"
 #define LAUNCH_JOBKEY_MACH_ENTERKERNELDEBUGGERONCLOSE  "EnterKernelDebuggerOnClose"
 
-typedef struct _launch *launch_t;
-
-launch_t launchd_fdopen(int, int);
-int launchd_getfd(launch_t);
-void launchd_close(launch_t, __typeof__(close) closefunc);
-
-launch_data_t   launch_data_new_errno(int);
-bool           launch_data_set_errno(launch_data_t, int);
-
-int launchd_msg_send(launch_t, launch_data_t);
-int launchd_msg_recv(launch_t, void (*)(launch_data_t, void *), void *);
+#define LAUNCH_ENV_INSTANCEID                                                  "LaunchInstanceID"
 
 /* For LoginWindow.
  *
 
 /* For LoginWindow.
  *
@@ -107,20 +108,13 @@ pid_t create_and_switch_to_per_session_launchd(const char * /* loginname */, int
  */
 void load_launchd_jobs_at_loginwindow_prompt(int flags, ...);
 
  */
 void load_launchd_jobs_at_loginwindow_prompt(int flags, ...);
 
-
-/* batch jobs will be implicity re-enabled when the last application who
- * disabled them exits.
- *
- * This API is really a hack to work around the lack of real-time APIs
- * at the VFS layer.
- */
-void launchd_batch_enable(bool);
-bool launchd_batch_query(void);
-
 /* For CoreProcesses
  */
 
 /* For CoreProcesses
  */
 
-#define SPAWN_VIA_LAUNCHD_STOPPED      0x0001
+#define SPAWN_VIA_LAUNCHD_STOPPED 0x0001
+#define SPAWN_VIA_LAUNCHD_TALAPP 0x0002
+#define SPAWN_VIA_LAUNCHD_WIDGET 0x0004
+#define SPAWN_VIA_LAUNCHD_DISABLE_ASLR 0x0008
 
 struct spawn_via_launchd_attr {
        uint64_t                spawn_flags;
 
 struct spawn_via_launchd_attr {
        uint64_t                spawn_flags;
@@ -136,18 +130,19 @@ struct spawn_via_launchd_attr {
        const uint64_t *        spawn_seatbelt_flags;
 };
 
        const uint64_t *        spawn_seatbelt_flags;
 };
 
-#define spawn_via_launchd(a, b, c) _spawn_via_launchd(a, b, c, 2)
+#define spawn_via_launchd(a, b, c) _spawn_via_launchd(a, b, c, 3)
 pid_t _spawn_via_launchd(
                const char *label,
                const char *const *argv,
                const struct spawn_via_launchd_attr *spawn_attrs,
                int struct_version);
 
 pid_t _spawn_via_launchd(
                const char *label,
                const char *const *argv,
                const struct spawn_via_launchd_attr *spawn_attrs,
                int struct_version);
 
+int launch_wait(mach_port_t port);
+
 kern_return_t mpm_wait(mach_port_t ajob, int *wstatus);
 
 kern_return_t mpm_uncork_fork(mach_port_t ajob);
 
 kern_return_t mpm_wait(mach_port_t ajob, int *wstatus);
 
 kern_return_t mpm_uncork_fork(mach_port_t ajob);
 
-
 __END_DECLS
 
 #pragma GCC visibility pop
 __END_DECLS
 
 #pragma GCC visibility pop
index fd1381eedc7e99f63d2e52e6ddea774518b655b6..3b86dcc8893a2ece8bf8f8bd4af9a5c0760292cd 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_APACHE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_APACHE_LICENSE_HEADER_START@
  * 
@@ -18,7 +18,7 @@
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
-static const char *const __rcs_file_version__ = "$Revision: 23930 $";
+static const char *const __rcs_file_version__ = "$Revision: 24957 $";
 
 #include "config.h"
 #include "launch.h"
 
 #include "config.h"
 #include "launch.h"
@@ -34,10 +34,6 @@ static const char *const __rcs_file_version__ = "$Revision: 23930 $";
 #include <CoreFoundation/CFPriv.h>
 #include <CoreFoundation/CFLogUtilities.h>
 #include <TargetConditionals.h>
 #include <CoreFoundation/CFPriv.h>
 #include <CoreFoundation/CFLogUtilities.h>
 #include <TargetConditionals.h>
-#if HAVE_SECURITY
-#include <Security/Security.h>
-#include <Security/AuthSession.h>
-#endif
 #include <IOKit/IOKitLib.h>
 #include <NSSystemDirectories.h>
 #include <mach/mach.h>
 #include <IOKit/IOKitLib.h>
 #include <NSSystemDirectories.h>
 #include <mach/mach.h>
@@ -65,6 +61,7 @@ static const char *const __rcs_file_version__ = "$Revision: 23930 $";
 #include <unistd.h>
 #include <dirent.h>
 #include <libgen.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <libgen.h>
+#include <libinfo.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -83,6 +80,7 @@ static const char *const __rcs_file_version__ = "$Revision: 23930 $";
 #include <util.h>
 #include <spawn.h>
 #include <sys/syslimits.h>
 #include <util.h>
 #include <spawn.h>
 #include <sys/syslimits.h>
+#include <fnmatch.h>
 
 #if HAVE_LIBAUDITD
 #include <bsm/auditd_lib.h>
 
 #if HAVE_LIBAUDITD
 #include <bsm/auditd_lib.h>
@@ -95,6 +93,7 @@ extern char **environ;
 
 
 #define LAUNCH_SECDIR _PATH_TMP "launch-XXXXXX"
 
 
 #define LAUNCH_SECDIR _PATH_TMP "launch-XXXXXX"
+#define LAUNCH_ENV_KEEPCONTEXT "LaunchKeepContext"
 
 #define MACHINIT_JOBKEY_ONDEMAND       "OnDemand"
 #define MACHINIT_JOBKEY_SERVICENAME    "ServiceName"
 
 #define MACHINIT_JOBKEY_ONDEMAND       "OnDemand"
 #define MACHINIT_JOBKEY_SERVICENAME    "ServiceName"
@@ -108,7 +107,6 @@ extern char **environ;
 #define CFTypeCheck(cf, type) (CFGetTypeID(cf) == type ## GetTypeID())
 
 struct load_unload_state {
 #define CFTypeCheck(cf, type) (CFGetTypeID(cf) == type ## GetTypeID())
 
 struct load_unload_state {
-       launch_data_t pass0;
        launch_data_t pass1;
        launch_data_t pass2;
        char *session_type;
        launch_data_t pass1;
        launch_data_t pass2;
        char *session_type;
@@ -137,13 +135,10 @@ static int _fd(int);
 static int demux_cmd(int argc, char *const argv[]);
 static launch_data_t do_rendezvous_magic(const struct addrinfo *res, const char *serv);
 static void submit_job_pass(launch_data_t jobs);
 static int demux_cmd(int argc, char *const argv[]);
 static launch_data_t do_rendezvous_magic(const struct addrinfo *res, const char *serv);
 static void submit_job_pass(launch_data_t jobs);
-static void submit_mach_jobs(launch_data_t jobs);
-static void let_go_of_mach_jobs(launch_data_t jobs);
 static void do_mgroup_join(int fd, int family, int socktype, int protocol, const char *mgroup);
 static mach_port_t str2bsport(const char *s);
 static void print_jobs(launch_data_t j, const char *key, void *context);
 static void print_obj(launch_data_t obj, const char *key, void *context);
 static void do_mgroup_join(int fd, int family, int socktype, int protocol, const char *mgroup);
 static mach_port_t str2bsport(const char *s);
 static void print_jobs(launch_data_t j, const char *key, void *context);
 static void print_obj(launch_data_t obj, const char *key, void *context);
-static bool is_legacy_mach_job(launch_data_t obj);
 static bool delay_to_second_pass(launch_data_t o);
 static void delay_to_second_pass2(launch_data_t o, const char *key, void *context);
 static bool str2lim(const char *buf, rlim_t *res);
 static bool delay_to_second_pass(launch_data_t o);
 static void delay_to_second_pass2(launch_data_t o, const char *key, void *context);
 static bool str2lim(const char *buf, rlim_t *res);
@@ -215,6 +210,7 @@ static int bstree_cmd(int argc __attribute__((unused)), char * const argv[] __at
 static int managerpid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused)));
 static int manageruid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused)));
 static int managername_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused)));
 static int managerpid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused)));
 static int manageruid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused)));
 static int managername_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused)));
+static int asuser_cmd(int argc, char * const argv[]);
 static int exit_cmd(int argc, char *const argv[]) __attribute__((noreturn));
 static int help_cmd(int argc, char *const argv[]);
 
 static int exit_cmd(int argc, char *const argv[]) __attribute__((noreturn));
 static int help_cmd(int argc, char *const argv[]);
 
@@ -251,6 +247,7 @@ static const struct {
        { "managerpid",         managerpid_cmd,                 "Print the PID of the launchd managing this Mach bootstrap." },
        { "manageruid",         manageruid_cmd,                 "Print the UID of the launchd managing this Mach bootstrap." },
        { "managername",        managername_cmd,                "Print the name of this Mach bootstrap." },
        { "managerpid",         managerpid_cmd,                 "Print the PID of the launchd managing this Mach bootstrap." },
        { "manageruid",         manageruid_cmd,                 "Print the UID of the launchd managing this Mach bootstrap." },
        { "managername",        managername_cmd,                "Print the name of this Mach bootstrap." },
+       { "asuser",                     asuser_cmd,                             "Execute a subcommand in the given user's context." },
        { "exit",                       exit_cmd,                               "Exit the interactive invocation of launchctl" },
        { "quit",                       exit_cmd,                               "Quit the interactive invocation of launchctl" },
        { "help",                       help_cmd,                               "This help output" },
        { "exit",                       exit_cmd,                               "Exit the interactive invocation of launchctl" },
        { "quit",                       exit_cmd,                               "Quit the interactive invocation of launchctl" },
        { "help",                       help_cmd,                               "This help output" },
@@ -265,6 +262,7 @@ static bool rootuser_context;
 static bool bootstrapping_system;
 static bool bootstrapping_peruser;
 static bool g_verbose_boot = false;
 static bool bootstrapping_system;
 static bool bootstrapping_peruser;
 static bool g_verbose_boot = false;
+static bool g_startup_debugging = false;
 
 static bool g_job_overrides_db_has_changed = false;
 static CFMutableDictionaryRef g_job_overrides_db = NULL;
 
 static bool g_job_overrides_db_has_changed = false;
 static CFMutableDictionaryRef g_job_overrides_db = NULL;
@@ -298,8 +296,8 @@ main(int argc, char *const argv[])
                                verbose = true;
                                break;
                        case 'u':
                                verbose = true;
                                break;
                        case 'u':
-                               if( argc > 1 ) {
-                                       if( strncmp(argv[1], "root", sizeof("root")) == 0 ) {
+                               if (argc > 1) {
+                                       if (strncmp(argv[1], "root", sizeof("root")) == 0) {
                                                rootuser_context = true;
                                        } else {
                                                fprintf(stderr, "Unknown user: %s\n", argv[1]);
                                                rootuser_context = true;
                                        } else {
                                                fprintf(stderr, "Unknown user: %s\n", argv[1]);
@@ -307,7 +305,7 @@ main(int argc, char *const argv[])
                                        }
                                        argc--, argv++;
                                } else {
                                        }
                                        argc--, argv++;
                                } else {
-                                       fprintf(stderr, "-u option requires an argument. Currently, only \"root\" is supported.\n");
+                                       fprintf(stderr, "-u option requires an argument.\n");
                                }
                                break;
                        case '1':
                                }
                                break;
                        case '1':
@@ -324,30 +322,30 @@ main(int argc, char *const argv[])
        /* Running in the context of the root user's per-user launchd is only supported ... well
         * in the root user's per-user context. I know it's confusing. I'm genuinely sorry.
         */
        /* Running in the context of the root user's per-user launchd is only supported ... well
         * in the root user's per-user context. I know it's confusing. I'm genuinely sorry.
         */
-       if( rootuser_context ) {
+       if (rootuser_context) {
                int64_t manager_uid = -1, manager_pid = -1;
                int64_t manager_uid = -1, manager_pid = -1;
-               if( vproc_swap_integer(NULL, VPROC_GSK_MGR_UID, NULL, &manager_uid) == NULL ) {
-                       if( vproc_swap_integer(NULL, VPROC_GSK_MGR_PID, NULL, &manager_pid) == NULL ) {
-                               if( manager_uid || manager_pid == 1 ) {
+               if (vproc_swap_integer(NULL, VPROC_GSK_MGR_UID, NULL, &manager_uid) == NULL) {
+                       if (vproc_swap_integer(NULL, VPROC_GSK_MGR_PID, NULL, &manager_pid) == NULL) {
+                               if (manager_uid || manager_pid == 1) {
                                        fprintf(stderr, "Running in the root user's per-user context is not supported outside of the root user's bootstrap.\n");
                                        exit(EXIT_FAILURE);
                                }
                        }
                }
                                        fprintf(stderr, "Running in the root user's per-user context is not supported outside of the root user's bootstrap.\n");
                                        exit(EXIT_FAILURE);
                                }
                        }
                }
-       } else if( !(system_context || rootuser_context) ) {
+       } else if (!(system_context || rootuser_context)) {
                /* Running in the system context is implied when we're running as root and not running as a bootstrapper. */
                /* Running in the system context is implied when we're running as root and not running as a bootstrapper. */
-               system_context = ( !is_managed && getuid() == 0 );
+               system_context = (!is_managed && getuid() == 0);
        }
 
        }
 
-       if( system_context ) {
-               if( getuid() == 0 ) {
+       if (system_context) {
+               if (getuid() == 0) {
                        setup_system_context();
                } else {
                        fprintf(stderr, "You must be root to run in the system context.\n");
                        exit(EXIT_FAILURE);
                }
                        setup_system_context();
                } else {
                        fprintf(stderr, "You must be root to run in the system context.\n");
                        exit(EXIT_FAILURE);
                }
-       } else if( rootuser_context ) {
-               if( getuid() != 0 ) {
+       } else if (rootuser_context) {
+               if (getuid() != 0) {
                        fprintf(stderr, "You must be root to run in the root user context.\n");
                        exit(EXIT_FAILURE);
                }
                        fprintf(stderr, "You must be root to run in the root user context.\n");
                        exit(EXIT_FAILURE);
                }
@@ -453,7 +451,7 @@ CFPropertyListRef CFPropertyListCreateFromFile(CFURLRef plistURL)
        CFReadStreamRef plistReadStream = CFReadStreamCreateWithFile(NULL, plistURL);
        
        CFErrorRef streamErr = NULL;
        CFReadStreamRef plistReadStream = CFReadStreamCreateWithFile(NULL, plistURL);
        
        CFErrorRef streamErr = NULL;
-       if( !CFReadStreamOpen(plistReadStream) ) {
+       if (!CFReadStreamOpen(plistReadStream)) {
                streamErr = CFReadStreamCopyError(plistReadStream);
                CFStringRef errString = CFErrorCopyDescription(streamErr);
                
                streamErr = CFReadStreamCopyError(plistReadStream);
                CFStringRef errString = CFErrorCopyDescription(streamErr);
                
@@ -464,11 +462,11 @@ CFPropertyListRef CFPropertyListCreateFromFile(CFURLRef plistURL)
        }
        
        CFPropertyListRef plist = NULL;
        }
        
        CFPropertyListRef plist = NULL;
-       if( plistReadStream ) {
+       if (plistReadStream) {
                CFStringRef errString = NULL;
                CFPropertyListFormat plistFormat = 0;
                plist = CFPropertyListCreateFromStream(NULL, plistReadStream, 0, kCFPropertyListImmutable, &plistFormat, &errString);
                CFStringRef errString = NULL;
                CFPropertyListFormat plistFormat = 0;
                plist = CFPropertyListCreateFromStream(NULL, plistReadStream, 0, kCFPropertyListImmutable, &plistFormat, &errString);
-               if( !plist ) {
+               if (!plist) {
                        CFShow(errString);
                        CFRelease(errString);
                }
                        CFShow(errString);
                        CFRelease(errString);
                }
@@ -480,7 +478,7 @@ CFPropertyListRef CFPropertyListCreateFromFile(CFURLRef plistURL)
        return plist;
 }
 
        return plist;
 }
 
-#define CFReleaseIfNotNULL(cf) if( cf ) CFRelease(cf);
+#define CFReleaseIfNotNULL(cf) if (cf) CFRelease(cf);
 void
 read_environment_dot_plist(void)
 {
 void
 read_environment_dot_plist(void)
 {
@@ -494,55 +492,55 @@ read_environment_dot_plist(void)
        snprintf(plist_path_str, sizeof(plist_path_str), "%s/.MacOSX/environment.plist", getenv("HOME"));
        
        struct stat sb;
        snprintf(plist_path_str, sizeof(plist_path_str), "%s/.MacOSX/environment.plist", getenv("HOME"));
        
        struct stat sb;
-       if( stat(plist_path_str, &sb) == -1 ) {
+       if (stat(plist_path_str, &sb) == -1) {
                goto out;
        }
        
        plistPath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), plist_path_str);
                goto out;
        }
        
        plistPath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), plist_path_str);
-       if( !assumes(plistPath != NULL) ) {
+       if (!assumes(plistPath != NULL)) {
                goto out;
        }
        
        plistURL = CFURLCreateWithFileSystemPath(NULL, plistPath, kCFURLPOSIXPathStyle, false);
                goto out;
        }
        
        plistURL = CFURLCreateWithFileSystemPath(NULL, plistPath, kCFURLPOSIXPathStyle, false);
-       if( !assumes(plistURL != NULL) ) {
+       if (!assumes(plistURL != NULL)) {
                goto out;
        }
        
        envPlist = (CFDictionaryRef)CFPropertyListCreateFromFile(plistURL);
                goto out;
        }
        
        envPlist = (CFDictionaryRef)CFPropertyListCreateFromFile(plistURL);
-       if( !assumes(envPlist != NULL) ) {
+       if (!assumes(envPlist != NULL)) {
                goto out;
        }
        
        launch_env_dict = CF2launch_data(envPlist);
                goto out;
        }
        
        launch_env_dict = CF2launch_data(envPlist);
-       if( !assumes(launch_env_dict != NULL) ) {
+       if (!assumes(launch_env_dict != NULL)) {
                goto out;
        }
        
        req = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
                goto out;
        }
        
        req = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
-       if( !assumes(req != NULL) ) {
+       if (!assumes(req != NULL)) {
                goto out;
        }
        
        launch_data_dict_insert(req, launch_env_dict, LAUNCH_KEY_SETUSERENVIRONMENT);
        resp = launch_msg(req);
                goto out;
        }
        
        launch_data_dict_insert(req, launch_env_dict, LAUNCH_KEY_SETUSERENVIRONMENT);
        resp = launch_msg(req);
-       if( !assumes(resp != NULL) ) {
+       if (!assumes(resp != NULL)) {
                goto out;
        }
        
                goto out;
        }
        
-       if( !assumes(launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) ) {
+       if (!assumes(launch_data_get_type(resp) == LAUNCH_DATA_ERRNO)) {
                goto out;
        }
 
                goto out;
        }
 
-       assumes(launch_data_get_errno(resp) == 0);
+       (void)assumes(launch_data_get_errno(resp) == 0);
 out:
        CFReleaseIfNotNULL(plistPath);
        CFReleaseIfNotNULL(plistURL);
        CFReleaseIfNotNULL(envPlist);   
 out:
        CFReleaseIfNotNULL(plistPath);
        CFReleaseIfNotNULL(plistURL);
        CFReleaseIfNotNULL(envPlist);   
-       if( req ) {
+       if (req) {
                launch_data_free(req);
        }
        
                launch_data_free(req);
        }
        
-       if( resp ) {
+       if (resp) {
                launch_data_free(resp);
        }
 }
                launch_data_free(resp);
        }
 }
@@ -664,24 +662,24 @@ getenv_and_export_cmd(int argc, char *const argv[])
 int
 wait4debugger_cmd(int argc, char * const argv[])
 {
 int
 wait4debugger_cmd(int argc, char * const argv[])
 {
-       if( argc != 3 ) {
+       if (argc != 3) {
                fprintf(stderr, "%s usage: debug <label> <value>\n", argv[0]);
                return 1;
        }
        
        int result = 1;
        int64_t inval = 0;
                fprintf(stderr, "%s usage: debug <label> <value>\n", argv[0]);
                return 1;
        }
        
        int result = 1;
        int64_t inval = 0;
-       if( strncmp(argv[2], "true", sizeof("true")) == 0 ) {
+       if (strncmp(argv[2], "true", sizeof("true")) == 0) {
                inval = 1;
                inval = 1;
-       } else if( strncmp(argv[2], "false", sizeof("false")) != 0 ) {
+       } else if (strncmp(argv[2], "false", sizeof("false")) != 0) {
                inval = atoi(argv[2]);
                inval &= 1;
        }
        
        vproc_t vp = vprocmgr_lookup_vproc(argv[1]);
                inval = atoi(argv[2]);
                inval &= 1;
        }
        
        vproc_t vp = vprocmgr_lookup_vproc(argv[1]);
-       if( vp ) {
+       if (vp) {
                vproc_err_t verr = vproc_swap_integer(vp, VPROC_GSK_WAITFORDEBUGGER, &inval, NULL);
                vproc_err_t verr = vproc_swap_integer(vp, VPROC_GSK_WAITFORDEBUGGER, &inval, NULL);
-               if( verr ) {
+               if (verr) {
                        fprintf(stderr, "Failed to set WaitForDebugger flag on %s.\n", argv[1]);
                } else {
                        result = 0;
                        fprintf(stderr, "Failed to set WaitForDebugger flag on %s.\n", argv[1]);
                } else {
                        result = 0;
@@ -712,10 +710,10 @@ unloadjob(launch_data_t job)
 void
 job_override(CFTypeRef key, CFTypeRef val, CFMutableDictionaryRef job)
 {
 void
 job_override(CFTypeRef key, CFTypeRef val, CFMutableDictionaryRef job)
 {
-       if( !CFTypeCheck(key, CFString) ) {
+       if (!CFTypeCheck(key, CFString)) {
                return;
        }
                return;
        }
-       if( CFStringCompare(key, CFSTR(LAUNCH_JOBKEY_LABEL), kCFCompareCaseInsensitive) == 0 ) {
+       if (CFStringCompare(key, CFSTR(LAUNCH_JOBKEY_LABEL), kCFCompareCaseInsensitive) == 0) {
                return;
        }
        
                return;
        }
        
@@ -728,23 +726,23 @@ read_plist_file(const char *file, bool editondisk, bool load)
        CFPropertyListRef plist = CreateMyPropertyListFromFile(file);
        launch_data_t r = NULL;
 
        CFPropertyListRef plist = CreateMyPropertyListFromFile(file);
        launch_data_t r = NULL;
 
-       if( NULL == plist ) {
+       if (NULL == plist) {
                fprintf(stderr, "%s: no plist was returned for: %s\n", getprogname(), file);
                return NULL;
        }
 
        CFStringRef label = CFDictionaryGetValue(plist, CFSTR(LAUNCH_JOBKEY_LABEL));
                fprintf(stderr, "%s: no plist was returned for: %s\n", getprogname(), file);
                return NULL;
        }
 
        CFStringRef label = CFDictionaryGetValue(plist, CFSTR(LAUNCH_JOBKEY_LABEL));
-       if( g_job_overrides_db && label && CFTypeCheck(label, CFString) ) {
+       if (g_job_overrides_db && label && CFTypeCheck(label, CFString)) {
                CFDictionaryRef overrides = CFDictionaryGetValue(g_job_overrides_db, label);
                CFDictionaryRef overrides = CFDictionaryGetValue(g_job_overrides_db, label);
-               if( overrides && CFTypeCheck(overrides, CFDictionary) ) {
+               if (overrides && CFTypeCheck(overrides, CFDictionary)) {
                        CFDictionaryApplyFunction(overrides, (CFDictionaryApplierFunction)job_override, (void *)plist);
                }
        }
 
                        CFDictionaryApplyFunction(overrides, (CFDictionaryApplierFunction)job_override, (void *)plist);
                }
        }
 
-       if( editondisk ) {
-               if( g_job_overrides_db ) {
+       if (editondisk) {
+               if (g_job_overrides_db) {
                        CFMutableDictionaryRef job = (CFMutableDictionaryRef)CFDictionaryGetValue(g_job_overrides_db, label);
                        CFMutableDictionaryRef job = (CFMutableDictionaryRef)CFDictionaryGetValue(g_job_overrides_db, label);
-                       if( !job || !CFTypeCheck(job, CFDictionary) ) {
+                       if (!job || !CFTypeCheck(job, CFDictionary)) {
                                job = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
                                CFDictionarySetValue(g_job_overrides_db, label, job);
                                CFRelease(job);
                                job = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
                                CFDictionarySetValue(g_job_overrides_db, label, job);
                                CFRelease(job);
@@ -811,6 +809,48 @@ delay_to_second_pass(launch_data_t o)
        return res;
 }
 
        return res;
 }
 
+static bool
+sysctl_hw_streq(int mib_slot, const char *str)
+{
+       char buf[1000];
+       size_t bufsz = sizeof(buf);
+       int mib[] = { CTL_HW, mib_slot };
+       
+       if (sysctl(mib, 2, buf, &bufsz, NULL, 0) != -1) {
+               if (strcmp(buf, str) == 0) {
+                       return true;
+               }
+       }
+       
+       return false;
+}
+
+static void
+limitloadtohardware_iterator(launch_data_t val, const char *key, void *ctx)
+{
+       bool *result = ctx;
+
+       char name[128];
+       (void)snprintf(name, sizeof(name), "hw.%s", key);
+
+       int mib[2];
+       size_t sz = 2;
+       if (*result != true && assumes(sysctlnametomib(name, mib, &sz) != -1)) {
+               if (launch_data_get_type(val) == LAUNCH_DATA_ARRAY) {
+                       size_t c = launch_data_array_get_count(val);
+                       
+                       size_t i = 0;
+                       for (i = 0; i < c; i++) {
+                               launch_data_t oai = launch_data_array_get_index(val, i);
+                               if (sysctl_hw_streq(mib[1], launch_data_get_string(oai))) {
+                                       *result = true;
+                                       i = c;
+                               }
+                       }
+               }
+       }
+}
+
 void
 readfile(const char *what, struct load_unload_state *lus)
 {
 void
 readfile(const char *what, struct load_unload_state *lus)
 {
@@ -825,17 +865,18 @@ readfile(const char *what, struct load_unload_state *lus)
                fprintf(stderr, "%s: no plist was returned for: %s\n", getprogname(), what);
                return;
        }
                fprintf(stderr, "%s: no plist was returned for: %s\n", getprogname(), what);
                return;
        }
-
-       if (is_legacy_mach_job(thejob)) {
-               fprintf(stderr, "%s: Please convert the following to launchd: %s\n", getprogname(), what);
-               launch_data_array_append(lus->pass0, thejob);
-               return;
-       }
+       
 
        if (NULL == launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LABEL)) {
                fprintf(stderr, "%s: missing the Label key: %s\n", getprogname(), what);
                goto out_bad;
        }
 
        if (NULL == launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LABEL)) {
                fprintf(stderr, "%s: missing the Label key: %s\n", getprogname(), what);
                goto out_bad;
        }
+       
+       if ((launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_PROGRAM) == NULL) && 
+               (launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_PROGRAMARGUMENTS) == NULL)) {
+               fprintf(stderr, "%s: neither a Program nor a ProgramArguments key was specified: %s", getprogname(), what);
+               goto out_bad;
+       }
 
        if (NULL != (tmpa = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADFROMHOSTS))) {
                c = launch_data_array_get_count(tmpa);
 
        if (NULL != (tmpa = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADFROMHOSTS))) {
                c = launch_data_array_get_count(tmpa);
@@ -863,6 +904,32 @@ readfile(const char *what, struct load_unload_state *lus)
                }
        }
 
                }
        }
 
+       if (NULL != (tmpd = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADTOHARDWARE))) {
+               bool result = false;
+               launch_data_dict_iterate(tmpd, limitloadtohardware_iterator, &result);
+               if (!result) {
+                       goto out_bad;
+               }
+       }
+
+       if (NULL != (tmpd = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADFROMHARDWARE))) {
+               bool result = false;
+               launch_data_dict_iterate(tmpd, limitloadtohardware_iterator, &result);
+               if (result) {
+                       goto out_bad;
+               }
+       }
+
+       // if the manager is Aqua, the LimitLoadToSessionType should default to 'Aqua'
+       // fixes <rdar://problem/8297909>
+       char *manager = "Bogus";
+       vproc_swap_string(NULL, VPROC_GSK_MGR_NAME, NULL, &manager);
+       if (!lus->session_type) {
+               if (strcmp(manager, "Aqua") == 0) {
+                       lus->session_type = "Aqua";
+               }
+       }
+
        if (lus->session_type && !(tmpa = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE))) {
                tmpa = launch_data_new_string("Aqua");
                launch_data_dict_insert(thejob, tmpa, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE);
        if (lus->session_type && !(tmpa = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE))) {
                tmpa = launch_data_new_string("Aqua");
                launch_data_dict_insert(thejob, tmpa, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE);
@@ -872,6 +939,19 @@ readfile(const char *what, struct load_unload_state *lus)
                const char *allowed_session;
                bool skipjob = true;
 
                const char *allowed_session;
                bool skipjob = true;
 
+               /* My sincere apologies to anyone who has to deal with this
+                * LimitLoadToSessionType madness. It was like this when I got here, but
+                * I've knowingly made it worse, hopefully to the benefit of the end
+                * user.
+                *
+                * See <rdar://problem/8769211> and <rdar://problem/7114980>.
+                */
+               if (!lus->session_type && launch_data_get_type(tmpa) == LAUNCH_DATA_STRING) {
+                       if (strcasecmp("System", manager) == 0 && strcasecmp("System", launch_data_get_string(tmpa)) == 0) {
+                               skipjob = false;
+                       }
+               }
+
                if (lus->session_type) switch (launch_data_get_type(tmpa)) {
                case LAUNCH_DATA_ARRAY:
                        c = launch_data_array_get_count(tmpa);
                if (lus->session_type) switch (launch_data_get_type(tmpa)) {
                case LAUNCH_DATA_ARRAY:
                        c = launch_data_array_get_count(tmpa);
@@ -914,7 +994,7 @@ readfile(const char *what, struct load_unload_state *lus)
                goto out_bad;
        }
        
                goto out_bad;
        }
        
-       if( bootstrapping_system || bootstrapping_peruser ) {
+       if (bootstrapping_system || bootstrapping_peruser) {
                uuid_t uuid;
                uuid_clear(uuid);
                
                uuid_t uuid;
                uuid_clear(uuid);
                
@@ -940,22 +1020,6 @@ out_bad:
        launch_data_free(thejob);
 }
 
        launch_data_free(thejob);
 }
 
-static bool
-sysctl_hw_streq(int mib_slot, const char *str)
-{
-       char buf[1000];
-       size_t bufsz = sizeof(buf);
-       int mib[] = { CTL_HW, mib_slot };
-
-       if (sysctl(mib, 2, buf, &bufsz, NULL, 0) != -1) {
-               if (strcmp(buf, str) == 0) {
-                       return true;
-               }
-       }
-
-       return false;
-}
-
 static void
 job_disabled_dict_logic(launch_data_t obj, const char *key, void *context)
 {
 static void
 job_disabled_dict_logic(launch_data_t obj, const char *key, void *context)
 {
@@ -1023,6 +1087,11 @@ path_goodness_check(const char *path, bool forceload)
                fprintf(stderr, "%s: Dubious path. Not a regular file or directory (skipping): %s\n", getprogname(), path);
                return false;
        }
                fprintf(stderr, "%s: Dubious path. Not a regular file or directory (skipping): %s\n", getprogname(), path);
                return false;
        }
+       
+       if ((!S_ISDIR(sb.st_mode)) && (fnmatch("*.plist", path, FNM_CASEFOLD) == FNM_NOMATCH)) {
+               fprintf(stderr, "%s: Dubious file. Not of type .plist (skipping): %s\n", getprogname(), path);
+               return false;
+       }
 
        return true;
 }
 
        return true;
 }
@@ -1451,11 +1520,11 @@ CreateMyPropertyListFromFile(const char *posixfile)
        }
        
        propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainersAndLeaves, &errorString);
        }
        
        propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainersAndLeaves, &errorString);
-       if( fileURL ) {
+       if (fileURL) {
                CFRelease(fileURL);
        }
        
                CFRelease(fileURL);
        }
        
-       if( resourceData ) {
+       if (resourceData) {
                CFRelease(resourceData);
        }
 
                CFRelease(resourceData);
        }
 
@@ -1481,7 +1550,7 @@ WriteMyPropertyListToFile(CFPropertyListRef plist, const char *posixfile)
                fprintf(stderr, "%s: CFURLWriteDataAndPropertiesToResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode);
        }
        
                fprintf(stderr, "%s: CFURLWriteDataAndPropertiesToResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode);
        }
        
-       if( resourceData ) {
+       if (resourceData) {
                CFRelease(resourceData);
        }
 }
                CFRelease(resourceData);
        }
 }
@@ -1490,7 +1559,7 @@ static inline Boolean __is_launch_data_t(launch_data_t obj)
 {
        Boolean result = true;
        
 {
        Boolean result = true;
        
-       switch( launch_data_get_type(obj) ) {
+       switch (launch_data_get_type(obj)) {
                case LAUNCH_DATA_STRING         : break;
                case LAUNCH_DATA_INTEGER        : break;
                case LAUNCH_DATA_REAL           : break;
                case LAUNCH_DATA_STRING         : break;
                case LAUNCH_DATA_INTEGER        : break;
                case LAUNCH_DATA_REAL           : break;
@@ -1507,11 +1576,11 @@ static inline Boolean __is_launch_data_t(launch_data_t obj)
 
 static void __launch_data_iterate(launch_data_t obj, const char *key, CFMutableDictionaryRef dict)
 {
 
 static void __launch_data_iterate(launch_data_t obj, const char *key, CFMutableDictionaryRef dict)
 {
-       if( obj && __is_launch_data_t(obj) ) {
+       if (obj && __is_launch_data_t(obj)) {
                CFStringRef cfKey = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
                CFTypeRef cfVal = CFTypeCreateFromLaunchData(obj);
                
                CFStringRef cfKey = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
                CFTypeRef cfVal = CFTypeCreateFromLaunchData(obj);
                
-               if( cfVal ) {
+               if (cfVal) {
                        CFDictionarySetValue(dict, cfKey, cfVal);
                        CFRelease(cfVal);
                }
                        CFDictionarySetValue(dict, cfKey, cfVal);
                        CFRelease(cfVal);
                }
@@ -1523,7 +1592,7 @@ static CFTypeRef CFTypeCreateFromLaunchData(launch_data_t obj)
 {
        CFTypeRef cfObj = NULL;
        
 {
        CFTypeRef cfObj = NULL;
        
-       switch( launch_data_get_type(obj) ) {
+       switch (launch_data_get_type(obj)) {
                case LAUNCH_DATA_STRING                 :
                {
                        const char *str = launch_data_get_string(obj);                  
                case LAUNCH_DATA_STRING                 :
                {
                        const char *str = launch_data_get_string(obj);                  
@@ -1590,15 +1659,15 @@ CFArrayRef CFArrayCreateFromLaunchArray(launch_data_t arr)
        CFArrayRef result = NULL;       
        CFMutableArrayRef mutResult = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
        
        CFArrayRef result = NULL;       
        CFMutableArrayRef mutResult = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
        
-       if( launch_data_get_type(arr) == LAUNCH_DATA_ARRAY ) {
+       if (launch_data_get_type(arr) == LAUNCH_DATA_ARRAY) {
                unsigned int count = launch_data_array_get_count(arr);
                unsigned int i = 0;
                
                unsigned int count = launch_data_array_get_count(arr);
                unsigned int i = 0;
                
-               for( i = 0; i < count; i++ ) {
+               for (i = 0; i < count; i++) {
                        launch_data_t launch_obj = launch_data_array_get_index(arr, i);
                        CFTypeRef obj = CFTypeCreateFromLaunchData(launch_obj);
                        
                        launch_data_t launch_obj = launch_data_array_get_index(arr, i);
                        CFTypeRef obj = CFTypeCreateFromLaunchData(launch_obj);
                        
-                       if( obj ) {
+                       if (obj) {
                                CFArrayAppendValue(mutResult, obj);
                                CFRelease(obj);
                        }
                                CFArrayAppendValue(mutResult, obj);
                                CFRelease(obj);
                        }
@@ -1607,7 +1676,7 @@ CFArrayRef CFArrayCreateFromLaunchArray(launch_data_t arr)
                result = CFArrayCreateCopy(NULL, mutResult);
        }
        
                result = CFArrayCreateCopy(NULL, mutResult);
        }
        
-       if( mutResult ) {
+       if (mutResult) {
                CFRelease(mutResult);
        }
        return result;
                CFRelease(mutResult);
        }
        return result;
@@ -1618,7 +1687,7 @@ static CFDictionaryRef CFDictionaryCreateFromLaunchDictionary(launch_data_t dict
 {
        CFDictionaryRef result = NULL;
        
 {
        CFDictionaryRef result = NULL;
        
-       if( launch_data_get_type(dict) == LAUNCH_DATA_DICTIONARY ) {
+       if (launch_data_get_type(dict) == LAUNCH_DATA_DICTIONARY) {
                CFMutableDictionaryRef mutResult = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
                
                launch_data_dict_iterate(dict, (void (*)(launch_data_t, const char *, void *))__launch_data_iterate, mutResult);
                CFMutableDictionaryRef mutResult = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
                
                launch_data_dict_iterate(dict, (void (*)(launch_data_t, const char *, void *))__launch_data_iterate, mutResult);
@@ -1670,7 +1739,7 @@ CF2launch_data(CFTypeRef cfr)
                r = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
                CFDictionaryApplyFunction(cfr, myCFDictionaryApplyFunction, r);
        } else if (cft == CFDataGetTypeID()) {
                r = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
                CFDictionaryApplyFunction(cfr, myCFDictionaryApplyFunction, r);
        } else if (cft == CFDataGetTypeID()) {
-               r = launch_data_alloc(LAUNCH_DATA_ARRAY);
+               r = launch_data_alloc(LAUNCH_DATA_OPAQUE);
                launch_data_set_opaque(r, CFDataGetBytePtr(cfr), CFDataGetLength(cfr));
        } else if (cft == CFNumberGetTypeID()) {
                long long n;
                launch_data_set_opaque(r, CFDataGetBytePtr(cfr), CFDataGetLength(cfr));
        } else if (cft == CFNumberGetTypeID()) {
                long long n;
@@ -1772,7 +1841,7 @@ do_single_user_mode2(void)
        case 0:
                break;
        default:
        case 0:
                break;
        default:
-               assumes(waitpid(p, &wstatus, 0) != -1);
+               (void)assumes(waitpid(p, &wstatus, 0) != -1);
                if (WIFEXITED(wstatus)) {
                        if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) {
                                return true;
                if (WIFEXITED(wstatus)) {
                        if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) {
                                return true;
@@ -1834,7 +1903,7 @@ do_crash_debug_mode2(void)
                case 0:
                        break;
                default:
                case 0:
                        break;
                default:
-                       assumes(waitpid(p, &wstatus, 0) != -1);
+                       (void)assumes(waitpid(p, &wstatus, 0) != -1);
                        if (WIFEXITED(wstatus)) {
                                if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) {
                                        return true;
                        if (WIFEXITED(wstatus)) {
                                if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) {
                                        return true;
@@ -1873,7 +1942,7 @@ do_crash_debug_mode2(void)
 static void
 exit_at_sigterm(int sig)
 {
 static void
 exit_at_sigterm(int sig)
 {
-       if( sig == SIGTERM ) {
+       if (sig == SIGTERM) {
                _exit(EXIT_SUCCESS);
        }
 }
                _exit(EXIT_SUCCESS);
        }
 }
@@ -1887,22 +1956,23 @@ fatal_signal_handler(int sig __attribute__((unused)), siginfo_t *si __attribute_
 void
 handle_system_bootstrapper_crashes_separately(void)
 {
 void
 handle_system_bootstrapper_crashes_separately(void)
 {
-       if( !g_verbose_boot ) {
+       if (!g_startup_debugging) {
                return;
        }
        
                return;
        }
        
+       fprintf(stdout, "com.apple.launchctl.System\t\t\t*** Handling system bootstrapper crashes separately. ***\n");
        struct sigaction fsa;
        
        fsa.sa_sigaction = fatal_signal_handler;
        fsa.sa_flags = SA_SIGINFO;
        sigemptyset(&fsa.sa_mask);
        
        struct sigaction fsa;
        
        fsa.sa_sigaction = fatal_signal_handler;
        fsa.sa_flags = SA_SIGINFO;
        sigemptyset(&fsa.sa_mask);
        
-       assumes(sigaction(SIGILL, &fsa, NULL) != -1);
-       assumes(sigaction(SIGFPE, &fsa, NULL) != -1);
-       assumes(sigaction(SIGBUS, &fsa, NULL) != -1);
-       assumes(sigaction(SIGSEGV, &fsa, NULL) != -1);
-       assumes(sigaction(SIGTRAP, &fsa, NULL) != -1);
-       assumes(sigaction(SIGABRT, &fsa, NULL) != -1);
+       (void)assumes(sigaction(SIGILL, &fsa, NULL) != -1);
+       (void)assumes(sigaction(SIGFPE, &fsa, NULL) != -1);
+       (void)assumes(sigaction(SIGBUS, &fsa, NULL) != -1);
+       (void)assumes(sigaction(SIGSEGV, &fsa, NULL) != -1);
+       (void)assumes(sigaction(SIGTRAP, &fsa, NULL) != -1);
+       (void)assumes(sigaction(SIGABRT, &fsa, NULL) != -1);
 }
 
 static void
 }
 
 static void
@@ -1915,20 +1985,26 @@ system_specific_bootstrap(bool sflag)
        launch_data_t lda, ldb;
 #endif
 
        launch_data_t lda, ldb;
 #endif
 
+       handle_system_bootstrapper_crashes_separately();
+
+       // Disable Libinfo lookups to mdns and ds while bootstrapping (8698260)
+       si_search_module_set_flags("mdns", 1);
+       si_search_module_set_flags("ds", 1);
+
        do_sysversion_sysctl();
 
        do_single_user_mode(sflag);
 
        do_sysversion_sysctl();
 
        do_single_user_mode(sflag);
 
-       assumes((kq = kqueue()) != -1);
+       (void)assumes((kq = kqueue()) != -1);
 
        EV_SET(&kev, 0, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, 60, 0);
 
        EV_SET(&kev, 0, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, 60, 0);
-       assumes(kevent(kq, &kev, 1, NULL, 0, NULL) != -1);
+       (void)assumes(kevent(kq, &kev, 1, NULL, 0, NULL) != -1);
 
        EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
 
        EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
-       assumes(kevent(kq, &kev, 1, NULL, 0, NULL) != -1);
-       assumes(signal(SIGTERM, SIG_IGN) != SIG_ERR);
+       (void)assumes(kevent(kq, &kev, 1, NULL, 0, NULL) != -1);
+       (void)assumes(signal(SIGTERM, SIG_IGN) != SIG_ERR);
 
 
-       assumes(sysctl(hnmib, 2, NULL, NULL, "localhost", sizeof("localhost")) != -1);
+       (void)assumes(sysctl(hnmib, 2, NULL, NULL, "localhost", sizeof("localhost")) != -1);
 
        loopback_setup_ipv4();
        loopback_setup_ipv6();
 
        loopback_setup_ipv4();
        loopback_setup_ipv6();
@@ -1939,8 +2015,8 @@ system_specific_bootstrap(bool sflag)
        if (path_check("/etc/rc.boot")) {
                const char *rcboot_tool[] = { "/etc/rc.boot", NULL };
                
        if (path_check("/etc/rc.boot")) {
                const char *rcboot_tool[] = { "/etc/rc.boot", NULL };
                
-               assumes(signal(SIGTERM, exit_at_sigterm) != SIG_ERR);
-               assumes(fwexec(rcboot_tool, NULL) != -1);
+               (void)assumes(signal(SIGTERM, exit_at_sigterm) != SIG_ERR);
+               (void)assumes(fwexec(rcboot_tool, NULL) != -1);
        }
 #endif
 
        }
 #endif
 
@@ -1950,60 +2026,70 @@ system_specific_bootstrap(bool sflag)
                /* The bootstrapper should always be killable during install-time (rdar://problem/6103485). 
                 * This is a special case for /etc/rc.cdrom, which runs a process and never exits.
                 */
                /* The bootstrapper should always be killable during install-time (rdar://problem/6103485). 
                 * This is a special case for /etc/rc.cdrom, which runs a process and never exits.
                 */
-               assumes(signal(SIGTERM, exit_at_sigterm) != SIG_ERR);
-               assumes(fwexec(rccdrom_tool, NULL) != -1);
-               assumes(reboot(RB_HALT) != -1);
+               (void)assumes(signal(SIGTERM, exit_at_sigterm) != SIG_ERR);
+               (void)assumes(fwexec(rccdrom_tool, NULL) != -1);
+               (void)assumes(reboot(RB_HALT) != -1);
                _exit(EXIT_FAILURE);
        } else if (is_netboot()) {
                const char *rcnetboot_tool[] = { _PATH_BSHELL, "/etc/rc.netboot", "init", NULL };
                if (!assumes(fwexec(rcnetboot_tool, NULL) != -1)) {
                _exit(EXIT_FAILURE);
        } else if (is_netboot()) {
                const char *rcnetboot_tool[] = { _PATH_BSHELL, "/etc/rc.netboot", "init", NULL };
                if (!assumes(fwexec(rcnetboot_tool, NULL) != -1)) {
-                       assumes(reboot(RB_HALT) != -1);
+                       (void)assumes(reboot(RB_HALT) != -1);
                        _exit(EXIT_FAILURE);
                }
        } else {
                do_potential_fsck();
        }
 
                        _exit(EXIT_FAILURE);
                }
        } else {
                do_potential_fsck();
        }
 
+#if TARGET_OS_EMBEDDED
+       if (path_check("/usr/libexec/cc_fips_test")) {
+               const char *fips_tool[] = { "/usr/libexec/cc_fips_test", "-P", NULL };
+               if (fwexec(fips_tool, NULL) == -1) {
+                       printf("FIPS self check failure\n");
+                       (void)assumes(reboot(RB_HALT) != -1);
+                       _exit(EXIT_FAILURE);
+               }
+       }
+#endif
+    
        if (path_check("/etc/rc.server")) {
                const char *rcserver_tool[] = { _PATH_BSHELL, "/etc/rc.server", NULL };
        if (path_check("/etc/rc.server")) {
                const char *rcserver_tool[] = { _PATH_BSHELL, "/etc/rc.server", NULL };
-               assumes(fwexec(rcserver_tool, NULL) != -1);
+               (void)assumes(fwexec(rcserver_tool, NULL) != -1);
        }
 
        read_launchd_conf();
        }
 
        read_launchd_conf();
-       handle_system_bootstrapper_crashes_separately();
 
        if (path_check("/var/account/acct")) {
 
        if (path_check("/var/account/acct")) {
-               assumes(acct("/var/account/acct") != -1);
+               (void)assumes(acct("/var/account/acct") != -1);
        }
 
 #if !TARGET_OS_EMBEDDED
        if (path_check("/etc/fstab")) {
                const char *mount_tool[] = { "mount", "-vat", "nonfs", NULL };
        }
 
 #if !TARGET_OS_EMBEDDED
        if (path_check("/etc/fstab")) {
                const char *mount_tool[] = { "mount", "-vat", "nonfs", NULL };
-               assumes(fwexec(mount_tool, NULL) != -1);
+               (void)assumes(fwexec(mount_tool, NULL) != -1);
        }
 #endif
 
        if (path_check("/etc/rc.installer_cleanup")) {
                const char *rccleanup_tool[] = { _PATH_BSHELL, "/etc/rc.installer_cleanup", "multiuser", NULL };
        }
 #endif
 
        if (path_check("/etc/rc.installer_cleanup")) {
                const char *rccleanup_tool[] = { _PATH_BSHELL, "/etc/rc.installer_cleanup", "multiuser", NULL };
-               assumes(fwexec(rccleanup_tool, NULL) != -1);
+               (void)assumes(fwexec(rccleanup_tool, NULL) != -1);
        }
 
        }
 
-       if( path_check("/etc/rc.deferred_install") ) {
+       if (path_check("/etc/rc.deferred_install")) {
                int status = 0;
                const char *deferredinstall_tool[] = { _PATH_BSHELL, "/etc/rc.deferred_install", NULL };
                int status = 0;
                const char *deferredinstall_tool[] = { _PATH_BSHELL, "/etc/rc.deferred_install", NULL };
-               if( assumes(fwexec(deferredinstall_tool, &status) != -1) ) {
-                       if( WEXITSTATUS(status) == EXIT_SUCCESS ) {
-                               if( do_apple_internal_magic ) {
+               if (assumes(fwexec(deferredinstall_tool, &status) != -1)) {
+                       if (WEXITSTATUS(status) == EXIT_SUCCESS) {
+                               if (do_apple_internal_magic) {
                                        fprintf(stdout, "Deferred install script completed successfully. Rebooting in 3 seconds...\n");
                                        sleep(3);
                                }
                                
                                        fprintf(stdout, "Deferred install script completed successfully. Rebooting in 3 seconds...\n");
                                        sleep(3);
                                }
                                
-                               assumes(remove(deferredinstall_tool[1]) != -1);
-                               assumes(reboot(RB_AUTOBOOT) != -1);
+                               (void)assumes(remove(deferredinstall_tool[1]) != -1);
+                               (void)assumes(reboot(RB_AUTOBOOT) != -1);
                                exit(EXIT_FAILURE);
                        } else {
                                fprintf(stdout, "Deferred install script exited with status %i. Continuing boot and hoping it'll work...\n", WEXITSTATUS(status));
                                exit(EXIT_FAILURE);
                        } else {
                                fprintf(stdout, "Deferred install script exited with status %i. Continuing boot and hoping it'll work...\n", WEXITSTATUS(status));
-                               assumes(remove(deferredinstall_tool[1]) != -1);
+                               (void)assumes(remove(deferredinstall_tool[1]) != -1);
                        }
                }
        }
                        }
                }
        }
@@ -2014,12 +2100,12 @@ system_specific_bootstrap(bool sflag)
 
        if (path_check("/usr/libexec/dirhelper")) {
                const char *dirhelper_tool[] = { "/usr/libexec/dirhelper", "-machineBoot", NULL };
 
        if (path_check("/usr/libexec/dirhelper")) {
                const char *dirhelper_tool[] = { "/usr/libexec/dirhelper", "-machineBoot", NULL };
-               assumes(fwexec(dirhelper_tool, NULL) != -1);
+               (void)assumes(fwexec(dirhelper_tool, NULL) != -1);
        }
 
        }
 
-       assumes(touch_file(_PATH_UTMPX, DEFFILEMODE) != -1);
+       (void)assumes(touch_file(_PATH_UTMPX, DEFFILEMODE) != -1);
 #if !TARGET_OS_EMBEDDED
 #if !TARGET_OS_EMBEDDED
-       assumes(touch_file(_PATH_VARRUN "/.systemStarterRunning", DEFFILEMODE) != -1);
+       (void)assumes(touch_file(_PATH_VARRUN "/.systemStarterRunning", DEFFILEMODE) != -1);
 #endif
 
 #if HAVE_LIBAUDITD
 #endif
 
 #if HAVE_LIBAUDITD
@@ -2030,13 +2116,13 @@ system_specific_bootstrap(bool sflag)
                ((ldb = launch_data_dict_lookup(lda, LAUNCH_JOBKEY_DISABLED)) == NULL ||
                 job_disabled_logic(ldb) == false)) 
        {
                ((ldb = launch_data_dict_lookup(lda, LAUNCH_JOBKEY_DISABLED)) == NULL ||
                 job_disabled_logic(ldb) == false)) 
        {
-               assumes(audit_quick_start() == 0);
+               (void)assumes(audit_quick_start() == 0);
                launch_data_free(lda);  
        }
 #else
        if (path_check("/etc/security/rc.audit")) {
                const char *audit_tool[] = { _PATH_BSHELL, "/etc/security/rc.audit", NULL };
                launch_data_free(lda);  
        }
 #else
        if (path_check("/etc/security/rc.audit")) {
                const char *audit_tool[] = { _PATH_BSHELL, "/etc/security/rc.audit", NULL };
-               assumes(fwexec(audit_tool, NULL) != -1);
+               (void)assumes(fwexec(audit_tool, NULL) != -1);
        }
 #endif
 
        }
 #endif
 
@@ -2046,14 +2132,14 @@ system_specific_bootstrap(bool sflag)
 
        _vproc_set_global_on_demand(true);
 
 
        _vproc_set_global_on_demand(true);
 
-       char *load_launchd_items[] = { "load", "-D", "all", "/etc/mach_init.d", NULL };
-       int load_launchd_items_cnt = 4;
+       char *load_launchd_items[] = { "load", "-D", "all", NULL };
+       int load_launchd_items_cnt = 3;
 
        if (is_safeboot()) {
                load_launchd_items[2] = "system";
        }
 
 
        if (is_safeboot()) {
                load_launchd_items[2] = "system";
        }
 
-       assumes(load_and_unload_cmd(load_launchd_items_cnt, load_launchd_items) == 0);
+       (void)assumes(load_and_unload_cmd(load_launchd_items_cnt, load_launchd_items) == 0);
 
        /*
         * 5066316
 
        /*
         * 5066316
@@ -2108,17 +2194,17 @@ system_specific_bootstrap(bool sflag)
 
        _vproc_set_global_on_demand(false);
 
 
        _vproc_set_global_on_demand(false);
 
-       assumes(kevent(kq, NULL, 0, &kev, 1, NULL) == 1);
-
-       do_BootCache_magic(BOOTCACHE_STOP);
+       (void)assumes(kevent(kq, NULL, 0, &kev, 1, NULL) == 1);
 
 
-       assumes(close(kq) != -1);
+       /* warmd now handles cutting off the BootCache. We just kick it off. */
+       
+       (void)assumes(close(kq) != -1);
 }
 
 void
 do_BootCache_magic(BootCache_action_t what)
 {
 }
 
 void
 do_BootCache_magic(BootCache_action_t what)
 {
-       const char *bcc_tool[] = { "/usr/sbin/BootCacheControl", "-f", "/var/db/BootCache.playlist", NULL, NULL };
+       const char *bcc_tool[] = { "/usr/sbin/BootCacheControl", NULL, NULL };
 
        if (is_safeboot() || !path_check(bcc_tool[0])) {
                return;
 
        if (is_safeboot() || !path_check(bcc_tool[0])) {
                return;
@@ -2126,17 +2212,14 @@ do_BootCache_magic(BootCache_action_t what)
 
        switch (what) {
        case BOOTCACHE_START:
 
        switch (what) {
        case BOOTCACHE_START:
-               bcc_tool[3] = "start";
+               bcc_tool[1] = "start";
                break;
        case BOOTCACHE_TAG:
                break;
        case BOOTCACHE_TAG:
-               bcc_tool[3] = "tag";
+               bcc_tool[1] = "tag";
                break;
        case BOOTCACHE_STOP:
                break;
        case BOOTCACHE_STOP:
-               bcc_tool[3] = "stop";
+               bcc_tool[1] = "stop";
                break;
                break;
-       default:
-               assumes(false);
-               return;
        }
 
        fwexec(bcc_tool, NULL);
        }
 
        fwexec(bcc_tool, NULL);
@@ -2226,16 +2309,16 @@ bootstrap_cmd(int argc, char *const argv[])
                        bootstrapping_peruser = true;
                        read_launchd_conf();
 #if 0 /* XXX PR-6456403 */
                        bootstrapping_peruser = true;
                        read_launchd_conf();
 #if 0 /* XXX PR-6456403 */
-                       assumes(SessionCreate(sessionKeepCurrentBootstrap, 0) == 0);
+                       (void)assumes(SessionCreate(sessionKeepCurrentBootstrap, 0) == 0);
 #endif
                }
 
                int retval = load_and_unload_cmd(the_argc, load_launchd_items);
 #endif
                }
 
                int retval = load_and_unload_cmd(the_argc, load_launchd_items);
-               if( retval == 0 && the_argc_user != 0 ) {
+               if (retval == 0 && the_argc_user != 0) {
                        optind = 1;
                        int64_t junk = 0;
                        vproc_err_t err = vproc_swap_integer(NULL, VPROC_GSK_WEIRD_BOOTSTRAP, &junk, NULL);
                        optind = 1;
                        int64_t junk = 0;
                        vproc_err_t err = vproc_swap_integer(NULL, VPROC_GSK_WEIRD_BOOTSTRAP, &junk, NULL);
-                       if( !err ) {
+                       if (!err) {
                                retval = load_and_unload_cmd(the_argc_user, load_launchd_items_user);
                        }
                }
                                retval = load_and_unload_cmd(the_argc_user, load_launchd_items_user);
                        }
                }
@@ -2313,7 +2396,7 @@ load_and_unload_cmd(int argc, char *const argv[])
        int dbfd = -1;
        char *db = NULL;
        vproc_err_t verr = vproc_swap_string(NULL, VPROC_GSK_JOB_OVERRIDES_DB, NULL, &db);
        int dbfd = -1;
        char *db = NULL;
        vproc_err_t verr = vproc_swap_string(NULL, VPROC_GSK_JOB_OVERRIDES_DB, NULL, &db);
-       if( verr ) {
+       if (verr) {
                fprintf(stderr, "Could not get location of job overrides database.\n");
                g_job_overrides_db_path[0] = 0;
        } else {
                fprintf(stderr, "Could not get location of job overrides database.\n");
                g_job_overrides_db_path[0] = 0;
        } else {
@@ -2322,10 +2405,10 @@ load_and_unload_cmd(int argc, char *const argv[])
                /* If we can't create or lock the overrides database, we'll fall back to writing to the
                 * plist file directly.
                 */
                /* If we can't create or lock the overrides database, we'll fall back to writing to the
                 * plist file directly.
                 */
-               assumes((dbfd = open(g_job_overrides_db_path, O_RDONLY | O_EXLOCK | O_CREAT, S_IRUSR | S_IWUSR)) != -1);
-               if( dbfd != -1 ) {
+               (void)assumes((dbfd = open(g_job_overrides_db_path, O_RDONLY | O_EXLOCK | O_CREAT, S_IRUSR | S_IWUSR)) != -1);
+               if (dbfd != -1) {
                        g_job_overrides_db = (CFMutableDictionaryRef)CreateMyPropertyListFromFile(g_job_overrides_db_path);
                        g_job_overrides_db = (CFMutableDictionaryRef)CreateMyPropertyListFromFile(g_job_overrides_db_path);
-                       if( !g_job_overrides_db ) {
+                       if (!g_job_overrides_db) {
                                g_job_overrides_db = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
                        }
                }
                                g_job_overrides_db = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
                        }
                }
@@ -2341,7 +2424,6 @@ load_and_unload_cmd(int argc, char *const argv[])
         * launchd doesn't have reload support right now.
         */
 
         * launchd doesn't have reload support right now.
         */
 
-       lus.pass0 = launch_data_alloc(LAUNCH_DATA_ARRAY);
        lus.pass1 = launch_data_alloc(LAUNCH_DATA_ARRAY);
        lus.pass2 = launch_data_alloc(LAUNCH_DATA_ARRAY);
 
        lus.pass1 = launch_data_alloc(LAUNCH_DATA_ARRAY);
        lus.pass2 = launch_data_alloc(LAUNCH_DATA_ARRAY);
 
@@ -2368,13 +2450,11 @@ load_and_unload_cmd(int argc, char *const argv[])
                readpath(argv[i], &lus);
        }
 
                readpath(argv[i], &lus);
        }
 
-       if (launch_data_array_get_count(lus.pass0) == 0 &&
-                       launch_data_array_get_count(lus.pass1) == 0 &&
+       if (launch_data_array_get_count(lus.pass1) == 0 &&
                        launch_data_array_get_count(lus.pass2) == 0) {
                if (!is_managed) {
                        fprintf(stderr, "nothing found to %s\n", lus.load ? "load" : "unload");
                }
                        launch_data_array_get_count(lus.pass2) == 0) {
                if (!is_managed) {
                        fprintf(stderr, "nothing found to %s\n", lus.load ? "load" : "unload");
                }
-               launch_data_free(lus.pass0);
                launch_data_free(lus.pass1);
                launch_data_free(lus.pass2);
                return is_managed ? 0 : 1;
                launch_data_free(lus.pass1);
                launch_data_free(lus.pass2);
                return is_managed ? 0 : 1;
@@ -2382,9 +2462,7 @@ load_and_unload_cmd(int argc, char *const argv[])
        
        if (lus.load) {
                distill_jobs(lus.pass1);
        
        if (lus.load) {
                distill_jobs(lus.pass1);
-               submit_mach_jobs(lus.pass0);
                submit_job_pass(lus.pass1);
                submit_job_pass(lus.pass1);
-               let_go_of_mach_jobs(lus.pass0);
                distill_jobs(lus.pass2);
                submit_job_pass(lus.pass2);
        } else {
                distill_jobs(lus.pass2);
                submit_job_pass(lus.pass2);
        } else {
@@ -2396,7 +2474,7 @@ load_and_unload_cmd(int argc, char *const argv[])
                }
        }
 
                }
        }
 
-       if( g_job_overrides_db_has_changed ) {
+       if (g_job_overrides_db_has_changed) {
                WriteMyPropertyListToFile(g_job_overrides_db, g_job_overrides_db_path);
        }
        
                WriteMyPropertyListToFile(g_job_overrides_db, g_job_overrides_db_path);
        }
        
@@ -2405,62 +2483,6 @@ load_and_unload_cmd(int argc, char *const argv[])
        return 0;
 }
 
        return 0;
 }
 
-void
-submit_mach_jobs(launch_data_t jobs)
-{
-       size_t i, c;
-
-       c = launch_data_array_get_count(jobs);
-
-       for (i = 0; i < c; i++) {
-               launch_data_t tmp, oai = launch_data_array_get_index(jobs, i);
-               const char *sn = NULL, *cmd = NULL;
-               bool d = true;
-               mach_port_t msr, msv;
-               kern_return_t kr;
-               uid_t u = getuid();
-
-               if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_ONDEMAND)))
-                       d = launch_data_get_bool(tmp);
-               if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_SERVICENAME)))
-                       sn = launch_data_get_string(tmp);
-               if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_COMMAND)))
-                       cmd = launch_data_get_string(tmp);
-
-               if ((kr = bootstrap_create_server(bootstrap_port, (char *)cmd, u, d, &msr)) != KERN_SUCCESS) {
-                       fprintf(stderr, "%s: bootstrap_create_server(): %s\n", getprogname(), bootstrap_strerror(kr));
-                       continue;
-               }
-               if ((kr = bootstrap_check_in(msr, (char*)sn, &msv)) != KERN_SUCCESS) {
-                       fprintf(stderr, "%s: bootstrap_check_in(): %s\n", getprogname(), bootstrap_strerror(kr));
-                       mach_port_mod_refs(mach_task_self(), msv, MACH_PORT_RIGHT_RECEIVE, -1);
-                       continue;
-               }
-               launch_data_dict_insert(oai, launch_data_new_machport(msr), MACHINIT_JOBKEY_SERVERPORT);
-               launch_data_dict_insert(oai, launch_data_new_machport(msv), MACHINIT_JOBKEY_SERVICEPORT);
-       }
-}
-
-void
-let_go_of_mach_jobs(launch_data_t jobs)
-{
-       size_t i, c = launch_data_array_get_count(jobs);
-
-       for (i = 0; i < c; i++) {
-               launch_data_t tmp, oai = launch_data_array_get_index(jobs, i);
-               if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_SERVICEPORT))) {
-                       mach_port_destroy(mach_task_self(), launch_data_get_machport(tmp));
-               } else {
-                       fprintf(stderr, "%s: ack! missing service port!\n", getprogname());
-               }
-               if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_SERVERPORT))) {
-                       mach_port_destroy(mach_task_self(), launch_data_get_machport(tmp));
-               } else {
-                       fprintf(stderr, "%s: ack! missing server port!\n", getprogname());
-               }
-       }
-}
-
 void
 submit_job_pass(launch_data_t jobs)
 {
 void
 submit_job_pass(launch_data_t jobs)
 {
@@ -2658,12 +2680,12 @@ list_cmd(int argc, char *const argv[])
        if (argc > 3) {
                fprintf(stderr, "usage: %s list [-x] [label]\n", getprogname());
                return 1;
        if (argc > 3) {
                fprintf(stderr, "usage: %s list [-x] [label]\n", getprogname());
                return 1;
-       } else if( argc >= 2 ) {
+       } else if (argc >= 2) {
                plist_output = ( strncmp(argv[1], "-x", sizeof("-x")) == 0 );
                label = plist_output ? argv[2] : argv[1];
        }
        
                plist_output = ( strncmp(argv[1], "-x", sizeof("-x")) == 0 );
                label = plist_output ? argv[2] : argv[1];
        }
        
-       if( label ) {
+       if (label) {
                msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
                launch_data_dict_insert(msg, launch_data_new_string(label), LAUNCH_KEY_GETJOB);
                
                msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
                launch_data_dict_insert(msg, launch_data_new_string(label), LAUNCH_KEY_GETJOB);
                
@@ -2674,13 +2696,13 @@ list_cmd(int argc, char *const argv[])
                        fprintf(stderr, "launch_msg(): %s\n", strerror(errno));
                        r = 1;
                } else if (launch_data_get_type(resp) == LAUNCH_DATA_DICTIONARY) {
                        fprintf(stderr, "launch_msg(): %s\n", strerror(errno));
                        r = 1;
                } else if (launch_data_get_type(resp) == LAUNCH_DATA_DICTIONARY) {
-                       if( plist_output ) {
+                       if (plist_output) {
                                CFDictionaryRef respDict = CFDictionaryCreateFromLaunchDictionary(resp);
                                CFStringRef plistStr = NULL;
                                CFDictionaryRef respDict = CFDictionaryCreateFromLaunchDictionary(resp);
                                CFStringRef plistStr = NULL;
-                               if( respDict ) {
+                               if (respDict) {
                                        CFDataRef plistData = CFPropertyListCreateXMLData(NULL, (CFPropertyListRef)respDict);
                                        CFRelease(respDict);
                                        CFDataRef plistData = CFPropertyListCreateXMLData(NULL, (CFPropertyListRef)respDict);
                                        CFRelease(respDict);
-                                       if( plistData ) {
+                                       if (plistData) {
                                                plistStr = CFStringCreateWithBytes(NULL, CFDataGetBytePtr(plistData), CFDataGetLength(plistData), kCFStringEncodingUTF8, false);
                                                CFRelease(plistData);
                                        } else {
                                                plistStr = CFStringCreateWithBytes(NULL, CFDataGetBytePtr(plistData), CFDataGetLength(plistData), kCFStringEncodingUTF8, false);
                                                CFRelease(plistData);
                                        } else {
@@ -2690,7 +2712,7 @@ list_cmd(int argc, char *const argv[])
                                        r = 1;
                                }
                                
                                        r = 1;
                                }
                                
-                               if( plistStr ) {
+                               if (plistStr) {
                                        CFShow(plistStr);
                                        CFRelease(plistStr);
                                        r = 0;
                                        CFShow(plistStr);
                                        CFRelease(plistStr);
                                        r = 0;
@@ -2705,7 +2727,7 @@ list_cmd(int argc, char *const argv[])
                        r = 1;
                        launch_data_free(resp);
                }
                        r = 1;
                        launch_data_free(resp);
                }
-       } else if( vproc_swap_complex(NULL, VPROC_GSK_ALLJOBS, NULL, &resp) == NULL ) {
+       } else if (vproc_swap_complex(NULL, VPROC_GSK_ALLJOBS, NULL, &resp) == NULL) {
                fprintf(stdout, "PID\tStatus\tLabel\n");
                launch_data_dict_iterate(resp, print_jobs, NULL);
                launch_data_free(resp);
                fprintf(stdout, "PID\tStatus\tLabel\n");
                launch_data_dict_iterate(resp, print_jobs, NULL);
                launch_data_free(resp);
@@ -2990,16 +3012,16 @@ limit_cmd(int argc, char *const argv[])
        lmts[which].rlim_max = hlim;
 
        bool maxfiles_exceeded = false;
        lmts[which].rlim_max = hlim;
 
        bool maxfiles_exceeded = false;
-       if( strncmp(argv[1], "maxfiles", sizeof("maxfiles")) == 0 ) {
-               if( argc > 2 ) {
+       if (strncmp(argv[1], "maxfiles", sizeof("maxfiles")) == 0) {
+               if (argc > 2) {
                        maxfiles_exceeded = ( strncmp(argv[2], "unlimited", sizeof("unlimited")) == 0 );
                }
                
                        maxfiles_exceeded = ( strncmp(argv[2], "unlimited", sizeof("unlimited")) == 0 );
                }
                
-               if( argc > 3 ) {
+               if (argc > 3) {
                        maxfiles_exceeded = ( maxfiles_exceeded || strncmp(argv[3], "unlimited", sizeof("unlimited")) == 0 );
                }
                
                        maxfiles_exceeded = ( maxfiles_exceeded || strncmp(argv[3], "unlimited", sizeof("unlimited")) == 0 );
                }
                
-               if( maxfiles_exceeded ) {
+               if (maxfiles_exceeded) {
                        fprintf(stderr, "Neither the hard nor soft limit for \"maxfiles\" can be unlimited. Please use a numeric parameter for both.\n");
                        return 1;
                }
                        fprintf(stderr, "Neither the hard nor soft limit for \"maxfiles\" can be unlimited. Please use a numeric parameter for both.\n");
                        return 1;
                }
@@ -3062,7 +3084,15 @@ umask_cmd(int argc, char *const argv[])
 void
 setup_system_context(void)
 {
 void
 setup_system_context(void)
 {
-       if( geteuid() != 0 ) {
+       if (getenv(LAUNCHD_SOCKET_ENV)) {
+               return;
+       }
+
+       if (getenv(LAUNCH_ENV_KEEPCONTEXT)) {
+               return;
+       }
+
+       if (geteuid() != 0) {
                fprintf(stderr, "You must be the root user to perform this operation.\n");
                return;
        }
                fprintf(stderr, "You must be the root user to perform this operation.\n");
                return;
        }
@@ -3229,7 +3259,7 @@ str2bsport(const char *s)
                                return 1;
                        }
                } while (getrootbs && last_bport != bport);
                                return 1;
                        }
                } while (getrootbs && last_bport != bport);
-       } else if( strcmp(s, "0") == 0 || strcmp(s, "NULL") == 0 ) {
+       } else if (strcmp(s, "0") == 0 || strcmp(s, "NULL") == 0) {
                bport = MACH_PORT_NULL;
        } else {
                int pid = atoi(s);
                bport = MACH_PORT_NULL;
        } else {
                int pid = atoi(s);
@@ -3275,6 +3305,7 @@ bsexec_cmd(int argc, char *const argv[])
        setgid(getgid());
        setuid(getuid());
 
        setgid(getgid());
        setuid(getuid());
 
+       setenv(LAUNCH_ENV_KEEPCONTEXT, "1", 1);
        if (fwexec((const char *const *)argv + 2, NULL) == -1) {
                fprintf(stderr, "%s bsexec failed: %s\n", getprogname(), strerror(errno));
                return 1;
        if (fwexec((const char *const *)argv + 2, NULL) == -1) {
                fprintf(stderr, "%s bsexec failed: %s\n", getprogname(), strerror(errno));
                return 1;
@@ -3310,7 +3341,7 @@ _bslist_cmd(mach_port_t bport, unsigned int depth, bool show_job, bool local_onl
        
        for (i = 0; i < service_cnt ; i++) {
                fprintf(stdout, "%*s%-3s%s", depth, "", bport_state((service_actives[i])), service_names[i]);
        
        for (i = 0; i < service_cnt ; i++) {
                fprintf(stdout, "%*s%-3s%s", depth, "", bport_state((service_actives[i])), service_names[i]);
-               if( show_job ) {
+               if (show_job) {
                        fprintf(stdout, " (%s)", service_jobs[i]);
                }
                fprintf(stdout, "\n");
                        fprintf(stdout, " (%s)", service_jobs[i]);
                }
                fprintf(stdout, "\n");
@@ -3324,19 +3355,19 @@ bslist_cmd(int argc, char *const argv[])
 {
        mach_port_t bport = bootstrap_port;
        bool show_jobs = false;
 {
        mach_port_t bport = bootstrap_port;
        bool show_jobs = false;
-       if( argc > 2 && strcmp(argv[2], "-j") == 0 ) {
+       if (argc > 2 && strcmp(argv[2], "-j") == 0) {
                show_jobs = true;
        }
        
                show_jobs = true;
        }
        
-       if( argc > 1 ) {
-               if( show_jobs ) {
+       if (argc > 1) {
+               if (show_jobs) {
                        bport = str2bsport(argv[1]);
                        bport = str2bsport(argv[1]);
-               } else if( strcmp(argv[1], "-j") == 0 ) {
+               } else if (strcmp(argv[1], "-j") == 0) {
                        show_jobs = true;
                }
        }
        
                        show_jobs = true;
                }
        }
        
-       if( bport == MACH_PORT_NULL ) {
+       if (bport == MACH_PORT_NULL) {
                fprintf(stderr, "Invalid bootstrap port\n");
                return 1;
        }
                fprintf(stderr, "Invalid bootstrap port\n");
                return 1;
        }
@@ -3347,7 +3378,7 @@ bslist_cmd(int argc, char *const argv[])
 int
 _bstree_cmd(mach_port_t bsport, unsigned int depth, bool show_jobs)
 {
 int
 _bstree_cmd(mach_port_t bsport, unsigned int depth, bool show_jobs)
 {
-       if( bsport == MACH_PORT_NULL ) {
+       if (bsport == MACH_PORT_NULL) {
                fprintf(stderr, "No root port!\n");
                return 1;
        }
                fprintf(stderr, "No root port!\n");
                return 1;
        }
@@ -3358,8 +3389,8 @@ _bstree_cmd(mach_port_t bsport, unsigned int depth, bool show_jobs)
        unsigned int cnt = 0;
        
        kern_return_t kr = bootstrap_lookup_children(bsport, &child_ports, &child_names, &child_props, (mach_msg_type_number_t *)&cnt);
        unsigned int cnt = 0;
        
        kern_return_t kr = bootstrap_lookup_children(bsport, &child_ports, &child_names, &child_props, (mach_msg_type_number_t *)&cnt);
-       if( kr != BOOTSTRAP_SUCCESS && kr != BOOTSTRAP_NO_CHILDREN ) {
-               if( kr == BOOTSTRAP_NOT_PRIVILEGED ) {
+       if (kr != BOOTSTRAP_SUCCESS && kr != BOOTSTRAP_NO_CHILDREN) {
+               if (kr == BOOTSTRAP_NOT_PRIVILEGED) {
                        fprintf(stderr, "You must be root to perform this operation.\n");
                } else {
                        fprintf(stderr, "bootstrap_lookup_children(): %d\n", kr);
                        fprintf(stderr, "You must be root to perform this operation.\n");
                } else {
                        fprintf(stderr, "bootstrap_lookup_children(): %d\n", kr);
@@ -3371,20 +3402,26 @@ _bstree_cmd(mach_port_t bsport, unsigned int depth, bool show_jobs)
        unsigned int i = 0;
        _bslist_cmd(bsport, depth, show_jobs, true);
        
        unsigned int i = 0;
        _bslist_cmd(bsport, depth, show_jobs, true);
        
-       for( i = 0; i < cnt; i++ ) {
+       for (i = 0; i < cnt; i++) {
                char *type = NULL;
                char *type = NULL;
-               if( child_props[i] & BOOTSTRAP_PROPERTY_PERUSER ) {
+               if (child_props[i] & BOOTSTRAP_PROPERTY_PERUSER) {
                        type = "Per-user";
                        type = "Per-user";
-               } else if( child_props[i] & BOOTSTRAP_PROPERTY_EXPLICITSUBSET ) {
+               } else if (child_props[i] & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) {
                        type = "Explicit Subset";
                        type = "Explicit Subset";
-               } else if( child_props[i] & BOOTSTRAP_PROPERTY_IMPLICITSUBSET ) {
+               } else if (child_props[i] & BOOTSTRAP_PROPERTY_IMPLICITSUBSET) {
                        type = "Implicit Subset";
                        type = "Implicit Subset";
-               } else if( child_props[i] & BOOTSTRAP_PROPERTY_MOVEDSUBSET ) {
+               } else if (child_props[i] & BOOTSTRAP_PROPERTY_MOVEDSUBSET) {
                        type = "Moved Subset";
                        type = "Moved Subset";
+               } else if (child_props[i] & BOOTSTRAP_PROPERTY_XPC_SINGLETON) {
+                       type = "XPC Singleton Domain";
+               } else if (child_props[i] & BOOTSTRAP_PROPERTY_XPC_DOMAIN) {
+                       type = "XPC Private Domain";
+               } else {
+                       type = "Unknown";
                }
                
                fprintf(stdout, "%*s%s (%s)/\n", depth, "", child_names[i], type);
                }
                
                fprintf(stdout, "%*s%s (%s)/\n", depth, "", child_names[i], type);
-               if( child_ports[i] != MACH_PORT_NULL ) {
+               if (child_ports[i] != MACH_PORT_NULL) {
                        _bstree_cmd(child_ports[i], depth + 4, show_jobs);
                }
        }
                        _bstree_cmd(child_ports[i], depth + 4, show_jobs);
                }
        }
@@ -3396,11 +3433,11 @@ int
 bstree_cmd(int argc, char * const argv[])
 {
        bool show_jobs = false;
 bstree_cmd(int argc, char * const argv[])
 {
        bool show_jobs = false;
-       if( geteuid() != 0 ) {
+       if (geteuid() != 0) {
                fprintf(stderr, "You must be root to perform this operation.\n");
                return 1;
        } else {
                fprintf(stderr, "You must be root to perform this operation.\n");
                return 1;
        } else {
-               if( argc == 2 && strcmp(argv[1], "-j") == 0 ) {
+               if (argc == 2 && strcmp(argv[1], "-j") == 0) {
                        show_jobs = true;
                }
                fprintf(stdout, "System/\n");
                        show_jobs = true;
                }
                fprintf(stdout, "System/\n");
@@ -3414,7 +3451,7 @@ managerpid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute
 {
        int64_t manager_pid = 0;
        vproc_err_t verr = vproc_swap_integer(NULL, VPROC_GSK_MGR_PID, NULL, (int64_t *)&manager_pid);
 {
        int64_t manager_pid = 0;
        vproc_err_t verr = vproc_swap_integer(NULL, VPROC_GSK_MGR_PID, NULL, (int64_t *)&manager_pid);
-       if( verr ) {
+       if (verr) {
                fprintf(stdout, "Unknown job manager!\n");
                return 1;
        }
                fprintf(stdout, "Unknown job manager!\n");
                return 1;
        }
@@ -3428,7 +3465,7 @@ manageruid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute
 {
        int64_t manager_uid = 0;
        vproc_err_t verr = vproc_swap_integer(NULL, VPROC_GSK_MGR_UID, NULL, (int64_t *)&manager_uid);
 {
        int64_t manager_uid = 0;
        vproc_err_t verr = vproc_swap_integer(NULL, VPROC_GSK_MGR_UID, NULL, (int64_t *)&manager_uid);
-       if( verr ) {
+       if (verr) {
                fprintf(stdout, "Unknown job manager!\n");
                return 1;
        }
                fprintf(stdout, "Unknown job manager!\n");
                return 1;
        }
@@ -3442,7 +3479,7 @@ managername_cmd(int argc __attribute__((unused)), char * const argv[] __attribut
 {
        char *manager_name = NULL;
        vproc_err_t verr = vproc_swap_string(NULL, VPROC_GSK_MGR_NAME, NULL, &manager_name);
 {
        char *manager_name = NULL;
        vproc_err_t verr = vproc_swap_string(NULL, VPROC_GSK_MGR_NAME, NULL, &manager_name);
-       if( verr ) {
+       if (verr) {
                fprintf(stdout, "Unknown job manager!\n");
                return 1;
        }
                fprintf(stdout, "Unknown job manager!\n");
                return 1;
        }
@@ -3453,14 +3490,66 @@ managername_cmd(int argc __attribute__((unused)), char * const argv[] __attribut
        return 0;
 }
 
        return 0;
 }
 
-bool
-is_legacy_mach_job(launch_data_t obj)
+int
+asuser_cmd(int argc, char * const argv[])
 {
 {
-       bool has_servicename = launch_data_dict_lookup(obj, MACHINIT_JOBKEY_SERVICENAME);
-       bool has_command = launch_data_dict_lookup(obj, MACHINIT_JOBKEY_COMMAND);
-       bool has_label = launch_data_dict_lookup(obj, LAUNCH_JOBKEY_LABEL);
+       /* This code plays fast and loose with Mach ports. Do NOT use it as any sort
+        * of reference for port handling. Or really anything else in this file.
+        */
+       uid_t req_uid = (uid_t)-2;
+       if (argc > 2) {
+               req_uid = atoi(argv[1]);
+               if (req_uid == (uid_t)-2) {
+                       fprintf(stderr, "You cannot run a command nobody.\n");
+                       return 1;
+               }
+       } else {
+               fprintf(stderr, "Usage: launchctl asuser <UID> <command> [arguments...].\n");
+               return 1;
+       }
+
+       if (geteuid() != 0) {
+               fprintf(stderr, "You must be root to run a command as another user.\n");
+               return 1;
+       }
+
+       mach_port_t rbs = MACH_PORT_NULL;
+       kern_return_t kr = bootstrap_get_root(bootstrap_port, &rbs);
+       if (kr != BOOTSTRAP_SUCCESS) {
+               fprintf(stderr, "bootstrap_get_root(): %u\n", kr);
+               return 1;
+       }
+
+       mach_port_t bp = MACH_PORT_NULL;
+       kr = bootstrap_look_up_per_user(rbs, NULL, req_uid, &bp);
+       if (kr != BOOTSTRAP_SUCCESS) {
+               fprintf(stderr, "bootstrap_look_up_per_user(): %u\n", kr);
+               return 1;
+       }
 
 
-       return has_command && has_servicename && !has_label;
+       bootstrap_port = bp;
+       kr = task_set_bootstrap_port(mach_task_self(), bp);
+       if (kr != KERN_SUCCESS) {
+               fprintf(stderr, "task_set_bootstrap_port(): 0x%x: %s\n", kr, mach_error_string(kr));
+               return 1;
+       }
+
+       name_t sockpath;
+       sockpath[0] = 0;
+       kr = _vprocmgr_getsocket(sockpath);
+       if (kr != BOOTSTRAP_SUCCESS) {
+               fprintf(stderr, "_vprocmgr_getsocket(): %u\n", kr);
+               return 1;
+       }
+
+       setenv(LAUNCHD_SOCKET_ENV, sockpath, 1);
+       setenv(LAUNCH_ENV_KEEPCONTEXT, "1", 1);
+       if (fwexec((const char *const *)argv + 2, NULL) == -1) {
+               fprintf(stderr, "Couldn't spawn command: %s\n", argv[2]);
+               return 1;
+       }
+       
+       return 0;
 }
 
 void
 }
 
 void
@@ -3504,7 +3593,7 @@ loopback_setup_ipv4(void)
 
        if (assumes(ioctl(s, SIOCGIFFLAGS, &ifr) != -1)) {
                ifr.ifr_flags |= IFF_UP;
 
        if (assumes(ioctl(s, SIOCGIFFLAGS, &ifr) != -1)) {
                ifr.ifr_flags |= IFF_UP;
-               assumes(ioctl(s, SIOCSIFFLAGS, &ifr) != -1);
+               (void)assumes(ioctl(s, SIOCSIFFLAGS, &ifr) != -1);
        }
 
        memset(&ifra, 0, sizeof(ifra));
        }
 
        memset(&ifra, 0, sizeof(ifra));
@@ -3516,9 +3605,9 @@ loopback_setup_ipv4(void)
        ((struct sockaddr_in *)&ifra.ifra_mask)->sin_addr.s_addr = htonl(IN_CLASSA_NET);
        ((struct sockaddr_in *)&ifra.ifra_mask)->sin_len = sizeof(struct sockaddr_in);
 
        ((struct sockaddr_in *)&ifra.ifra_mask)->sin_addr.s_addr = htonl(IN_CLASSA_NET);
        ((struct sockaddr_in *)&ifra.ifra_mask)->sin_len = sizeof(struct sockaddr_in);
 
-       assumes(ioctl(s, SIOCAIFADDR, &ifra) != -1);
+       (void)assumes(ioctl(s, SIOCAIFADDR, &ifra) != -1);
 
 
-       assumes(close(s) == 0);
+       (void)assumes(close(s) == 0);
 }
 
 void
 }
 
 void
@@ -3539,7 +3628,7 @@ loopback_setup_ipv6(void)
 
        if (assumes(ioctl(s6, SIOCGIFFLAGS, &ifr) != -1)) {
                ifr.ifr_flags |= IFF_UP;
 
        if (assumes(ioctl(s6, SIOCGIFFLAGS, &ifr) != -1)) {
                ifr.ifr_flags |= IFF_UP;
-               assumes(ioctl(s6, SIOCSIFFLAGS, &ifr) != -1);
+               (void)assumes(ioctl(s6, SIOCSIFFLAGS, &ifr) != -1);
        }
 
        memset(&ifra6, 0, sizeof(ifra6));
        }
 
        memset(&ifra6, 0, sizeof(ifra6));
@@ -3554,9 +3643,11 @@ loopback_setup_ipv6(void)
        ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
        ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
 
        ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
        ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
 
-       assumes(ioctl(s6, SIOCAIFADDR_IN6, &ifra6) != -1);
+       if (ioctl(s6, SIOCAIFADDR_IN6, &ifra6) == -1) {
+               (void)assumes(errno == EEXIST);
+       }
 
 
-       assumes(close(s6) == 0);
+       (void)assumes(close(s6) == 0);
 }
 
 pid_t
 }
 
 pid_t
@@ -3566,7 +3657,6 @@ fwexec(const char *const *argv, int *wstatus)
        pid_t p;
 
        /* We'd use posix_spawnp(), but we want to workaround: 6288899 */
        pid_t p;
 
        /* We'd use posix_spawnp(), but we want to workaround: 6288899 */
-
        if ((p = vfork()) == -1) {
                return -1;
        } else if (p == 0) {
        if ((p = vfork()) == -1) {
                return -1;
        } else if (p == 0) {
@@ -3591,8 +3681,11 @@ void
 do_potential_fsck(void)
 {
        const char *safe_fsck_tool[] = { "fsck", "-fy", NULL };
 do_potential_fsck(void)
 {
        const char *safe_fsck_tool[] = { "fsck", "-fy", NULL };
-       const char *fsck_tool[] = { "fsck", "-p", NULL };
+       const char *fsck_tool[] = { "fsck", "-q", NULL };
        const char *remount_tool[] = { "mount", "-uw", "/", NULL };
        const char *remount_tool[] = { "mount", "-uw", "/", NULL };
+#if TARGET_OS_EMBEDDED
+       const char *nvram_tool[] = { "/usr/sbin/nvram", "auto-boot=false", NULL };
+#endif
        struct statfs sfs;
 
        if (!assumes(statfs("/", &sfs) != -1)) {
        struct statfs sfs;
 
        if (!assumes(statfs("/", &sfs) != -1)) {
@@ -3616,6 +3709,7 @@ do_potential_fsck(void)
                }
        }
 
                }
        }
 
+       fprintf(stdout, "Running safe fsck on the boot volume...\n");
        if (fwexec(safe_fsck_tool, NULL) != -1) {
                goto out;
        }
        if (fwexec(safe_fsck_tool, NULL) != -1) {
                goto out;
        }
@@ -3623,7 +3717,12 @@ do_potential_fsck(void)
        fprintf(stdout, "fsck failed!\n");
 
        /* someday, we should keep booting read-only, but as of today, other sub-systems cannot handle that scenario */
        fprintf(stdout, "fsck failed!\n");
 
        /* someday, we should keep booting read-only, but as of today, other sub-systems cannot handle that scenario */
-       assumes(reboot(RB_HALT) != -1);
+#if TARGET_OS_EMBEDDED
+       (void)assumes(fwexec(nvram_tool, NULL) != -1);
+       (void)assumes(reboot(RB_AUTOBOOT) != -1);
+#else
+       (void)assumes(reboot(RB_HALT) != -1);
+#endif
 
        return;
 out:
 
        return;
 out:
@@ -3639,11 +3738,14 @@ out:
 #if TARGET_OS_EMBEDDED
        if (path_check("/etc/fstab")) {
                const char *mount_tool[] = { "mount", "-vat", "nonfs", NULL };
 #if TARGET_OS_EMBEDDED
        if (path_check("/etc/fstab")) {
                const char *mount_tool[] = { "mount", "-vat", "nonfs", NULL };
-               assumes(fwexec(mount_tool, NULL) != -1);
+               if (!assumes(fwexec(mount_tool, NULL) != -1)) {
+                       (void)assumes(fwexec(nvram_tool, NULL) != -1);
+                       (void)assumes(reboot(RB_AUTOBOOT) != -1);
+               }
        } else
 #endif
        {
        } else
 #endif
        {
-               assumes(fwexec(remount_tool, NULL) != -1);
+               (void)assumes(fwexec(remount_tool, NULL) != -1);
        }
 
        fix_bogus_file_metadata();
        }
 
        fix_bogus_file_metadata();
@@ -3665,7 +3767,14 @@ fix_bogus_file_metadata(void)
                { _PATH_VARTMP, 0, 0, S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO, S_ISUID|S_ISGID, true },
                { "/var/folders", 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_ISUID | S_ISGID, true },
                { LAUNCHD_DB_PREFIX, 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH, true },
                { _PATH_VARTMP, 0, 0, S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO, S_ISUID|S_ISGID, true },
                { "/var/folders", 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_ISUID | S_ISGID, true },
                { LAUNCHD_DB_PREFIX, 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH, true },
-               { LAUNCHD_DB_PREFIX "/com.apple.launchd", 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH, true }
+               { LAUNCHD_DB_PREFIX "/com.apple.launchd", 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH, true },
+               // Fixing <rdar://problem/7571633>.
+               { _PATH_VARDB, 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH | S_ISUID | S_ISGID, true },
+               { _PATH_VARDB "mds/", 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH | S_ISUID | S_ISGID, true },
+#if !TARGET_OS_EMBEDDED
+               // Similar fix for <rdar://problem/6550172>.
+               { "/Library/StartupItems", 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH | S_ISUID | S_ISGID, true },
+#endif
        };
        struct stat sb;
        size_t i;
        };
        struct stat sb;
        size_t i;
@@ -3678,10 +3787,10 @@ fix_bogus_file_metadata(void)
 
                if (!assumes(stat(f[i].path, &sb) != -1)) {
                        fprintf(stdout, "Crucial filesystem check: Path not present: %s. %s\n", f[i].path, f[i].create ? "Will create." : "");
 
                if (!assumes(stat(f[i].path, &sb) != -1)) {
                        fprintf(stdout, "Crucial filesystem check: Path not present: %s. %s\n", f[i].path, f[i].create ? "Will create." : "");
-                       if( f[i].create ) {
-                               if( !assumes(mkdir(f[i].path, f[i].needed_bits) != -1) ) {
+                       if (f[i].create) {
+                               if (!assumes(mkdir(f[i].path, f[i].needed_bits) != -1)) {
                                        continue;
                                        continue;
-                               } else if( !assumes(stat(f[i].path, &sb) != -1) ) {
+                               } else if (!assumes(stat(f[i].path, &sb) != -1)) {
                                        continue;
                                }
                        } else {
                                        continue;
                                }
                        } else {
@@ -3710,10 +3819,10 @@ fix_bogus_file_metadata(void)
                }
 
                if (fix_mode) {
                }
 
                if (fix_mode) {
-                       assumes(chmod(f[i].path, (sb.st_mode & ~i_bad_bits) | i_needed_bits) != -1);
+                       (void)assumes(chmod(f[i].path, (sb.st_mode & ~i_bad_bits) | i_needed_bits) != -1);
                }
                if (fix_id) {
                }
                if (fix_id) {
-                       assumes(chown(f[i].path, f[i].owner, f[i].group) != -1);
+                       (void)assumes(chown(f[i].path, f[i].owner, f[i].group) != -1);
                }
        }
 }
                }
        }
 }
@@ -3798,7 +3907,7 @@ empty_dir(const char *thedir, struct stat *psb)
                }
 
                if (psb->st_dev != sb.st_dev) {
                }
 
                if (psb->st_dev != sb.st_dev) {
-                       assumes(unmount(de->d_name, MNT_FORCE) != -1);
+                       (void)assumes(unmount(de->d_name, MNT_FORCE) != -1);
 
                        /* Let's lstat() again to see if the unmount() worked and what was under it */
                        if (!assumes(lstat(de->d_name, &sb) != -1)) {
 
                        /* Let's lstat() again to see if the unmount() worked and what was under it */
                        if (!assumes(lstat(de->d_name, &sb) != -1)) {
@@ -3814,15 +3923,15 @@ empty_dir(const char *thedir, struct stat *psb)
                        empty_dir(de->d_name, &sb);
                }
 
                        empty_dir(de->d_name, &sb);
                }
 
-               assumes(lchflags(de->d_name, 0) != -1);
-               assumes(remove(de->d_name) != -1);
+               (void)assumes(lchflags(de->d_name, 0) != -1);
+               (void)assumes(remove(de->d_name) != -1);
        }
 
        }
 
-       assumes(closedir(od) != -1);
+       (void)assumes(closedir(od) != -1);
 
 out:
 
 out:
-       assumes(fchdir(currend_dir_fd) != -1);
-       assumes(close(currend_dir_fd) != -1);
+       (void)assumes(fchdir(currend_dir_fd) != -1);
+       (void)assumes(close(currend_dir_fd) != -1);
 }
 
 int
 }
 
 int
@@ -3868,19 +3977,48 @@ apply_sysctls_from_file(const char *thefile)
                        goto skip_sysctl_tool;
                }
                sysctl_tool[2] = val;
                        goto skip_sysctl_tool;
                }
                sysctl_tool[2] = val;
-               assumes(fwexec(sysctl_tool, NULL) != -1);
+               (void)assumes(fwexec(sysctl_tool, NULL) != -1);
 skip_sysctl_tool:
                free(tmpstr);
        }
 
 skip_sysctl_tool:
                free(tmpstr);
        }
 
-       assumes(fclose(sf) == 0);
+       (void)assumes(fclose(sf) == 0);
+}
+
+static CFStringRef
+copySystemBuildVersion(void)
+{
+    CFStringRef build = NULL;
+    const char path[] = "/System/Library/CoreServices/SystemVersion.plist";
+    CFURLRef plistURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (const uint8_t *)path, sizeof(path) - 1, false);
+
+       CFPropertyListRef plist = NULL;
+    if (plistURL && (plist = CFPropertyListCreateFromFile(plistURL))) {
+               if (CFTypeCheck(plist, CFDictionary)) {
+                       build = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionBuildVersionKey);
+                       if (build && CFTypeCheck(build, CFString)) {
+                               CFRetain(build);
+                       } else {
+                               build = CFSTR("99Z999");
+                       }
+               }
+
+               CFRelease(plist);
+    } else {
+               build = CFSTR("99Z999");
+       }
+
+       if (plistURL) {
+               CFRelease(plistURL);
+       }
+
+    return build;
 }
 
 void
 do_sysversion_sysctl(void)
 {
        int mib[] = { CTL_KERN, KERN_OSVERSION };
 }
 
 void
 do_sysversion_sysctl(void)
 {
        int mib[] = { CTL_KERN, KERN_OSVERSION };
-       CFDictionaryRef versdict;
        CFStringRef buildvers;
        char buf[1024];
        size_t bufsz = sizeof(buf);
        CFStringRef buildvers;
        char buf[1024];
        size_t bufsz = sizeof(buf);
@@ -3896,17 +4034,13 @@ do_sysversion_sysctl(void)
                return;
        }
 
                return;
        }
 
-       if (!assumes((versdict = _CFCopySystemVersionDictionary()))) {
-               return;
-       }
-
-       if (assumes((buildvers = CFDictionaryGetValue(versdict, _kCFSystemVersionBuildVersionKey)))) {
+       buildvers = copySystemBuildVersion();
+       if (assumes(buildvers)) {
                CFStringGetCString(buildvers, buf, sizeof(buf), kCFStringEncodingUTF8);
                CFStringGetCString(buildvers, buf, sizeof(buf), kCFStringEncodingUTF8);
-
-               assumes(sysctl(mib, 2, NULL, 0, buf, strlen(buf) + 1) != -1);
+               (void)assumes(sysctl(mib, 2, NULL, 0, buf, strlen(buf) + 1) != -1);
        }
 
        }
 
-       CFRelease(versdict);
+       CFRelease(buildvers);
 }
 
 void
 }
 
 void
@@ -3965,7 +4099,7 @@ do_application_firewall_magic(int sfd, launch_data_t thejob)
 
        if (assumes(prog != NULL)) {
                /* The networking team has asked us to ignore the failure of this API if errno == ENOPROTOOPT */
 
        if (assumes(prog != NULL)) {
                /* The networking team has asked us to ignore the failure of this API if errno == ENOPROTOOPT */
-               assumes(setsockopt(sfd, SOL_SOCKET, SO_EXECPATH, prog, (socklen_t)(strlen(prog) + 1)) != -1 || errno == ENOPROTOOPT);
+               (void)assumes(setsockopt(sfd, SOL_SOCKET, SO_EXECPATH, prog, (socklen_t)(strlen(prog) + 1)) != -1 || errno == ENOPROTOOPT);
        }
 }
 
        }
 }
 
@@ -3998,7 +4132,7 @@ preheat_page_cache_hack(void)
 
                if (fstat(fd, &sb) != -1) { 
                        if ((sb.st_size < 10*1024*1024) && (junkbuf = malloc((size_t)sb.st_size)) != NULL) {
 
                if (fstat(fd, &sb) != -1) { 
                        if ((sb.st_size < 10*1024*1024) && (junkbuf = malloc((size_t)sb.st_size)) != NULL) {
-                               assumes(read(fd, junkbuf, (size_t)sb.st_size) == (ssize_t)sb.st_size);
+                               (void)assumes(read(fd, junkbuf, (size_t)sb.st_size) == (ssize_t)sb.st_size);
                                free(junkbuf);
                        }
                }
                                free(junkbuf);
                        }
                }
@@ -4040,7 +4174,7 @@ do_bootroot_magic(void)
        }
 
        if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == EX_OSFILE) {
        }
 
        if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == EX_OSFILE) {
-               assumes(reboot(RB_AUTOBOOT) != -1);
+               (void)assumes(reboot(RB_AUTOBOOT) != -1);
        }
 }
 
        }
 }
 
@@ -4054,9 +4188,13 @@ do_file_init(void)
        }
 
        char bootargs[128];
        }
 
        char bootargs[128];
-       size_t len = sizeof(bootargs) - 1;
+       size_t len = sizeof(bootargs);
        int r = sysctlbyname("kern.bootargs", bootargs, &len, NULL, 0);
        int r = sysctlbyname("kern.bootargs", bootargs, &len, NULL, 0);
-       if( r == 0 && stat("/var/db/.launchd_shutdown_debugging", &sb) == 0 && strnstr(bootargs, "-v", len) != NULL ) {
+       if (r == 0 && (strnstr(bootargs, "-v", len) != NULL || strnstr(bootargs, "-s", len))) {
                g_verbose_boot = true;
        }
                g_verbose_boot = true;
        }
+       
+       if (stat("/var/db/.launchd_shutdown_debugging", &sb) == 0 && g_verbose_boot) {
+               g_startup_debugging = true;
+       }
 }
 }
index a9a2033e363330c2cad9716f59339104711559e3..78e173826f94899d7dc40d1a2e22b8e26310ba81 100644 (file)
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
-static const char *const __rcs_file_version__ = "$Revision: 23925 $";
+static const char *const __rcs_file_version__ = "$Revision: 24863 $";
 
 #include "config.h"
 #include "launchd.h"
 
 
 #include "config.h"
 #include "launchd.h"
 
-#if HAVE_SECURITY
-#include <Security/Authorization.h>
-#include <Security/AuthorizationTags.h>
-#include <Security/AuthSession.h>
-#endif
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/event.h>
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/event.h>
@@ -74,6 +69,7 @@ static const char *const __rcs_file_version__ = "$Revision: 23925 $";
 
 #if HAVE_LIBAUDITD
 #include <bsm/auditd_lib.h>
 
 #if HAVE_LIBAUDITD
 #include <bsm/auditd_lib.h>
+#include <bsm/audit_session.h>
 #endif
 
 #include "bootstrap.h"
 #endif
 
 #include "bootstrap.h"
@@ -88,7 +84,6 @@ static const char *const __rcs_file_version__ = "$Revision: 23925 $";
 #include "launchd_unix_ipc.h"
 
 #define LAUNCHD_CONF ".launchd.conf"
 #include "launchd_unix_ipc.h"
 
 #define LAUNCHD_CONF ".launchd.conf"
-#define SECURITY_LIB "/System/Library/Frameworks/Security.framework/Versions/A/Security"
 
 extern char **environ;
 
 
 extern char **environ;
 
@@ -103,9 +98,9 @@ static bool get_network_state(void);
 static void monitor_networking_state(void);
 static void fatal_signal_handler(int sig, siginfo_t *si, void *uap);
 static void handle_pid1_crashes_separately(void);
 static void monitor_networking_state(void);
 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(void);
+static void do_pid1_crash_diagnosis_mode(const char *msg);
 static int basic_fork(void);
 static int basic_fork(void);
-static bool do_pid1_crash_diagnosis_mode2(void);
+static bool do_pid1_crash_diagnosis_mode2(const char *msg);
 
 static void *update_thread(void *nothing);
 
 
 static void *update_thread(void *nothing);
 
@@ -132,7 +127,7 @@ main(int argc, char *const *argv)
        testfd_or_openfd(STDOUT_FILENO, _PATH_DEVNULL, O_WRONLY);
        testfd_or_openfd(STDERR_FILENO, _PATH_DEVNULL, O_WRONLY);
 
        testfd_or_openfd(STDOUT_FILENO, _PATH_DEVNULL, O_WRONLY);
        testfd_or_openfd(STDERR_FILENO, _PATH_DEVNULL, O_WRONLY);
 
-       if (pid1_magic && g_use_gmalloc) {
+       if (g_use_gmalloc) {
                if (!getenv("DYLD_INSERT_LIBRARIES")) {
                        setenv("DYLD_INSERT_LIBRARIES", "/usr/lib/libgmalloc.dylib", 1);
                        setenv("MALLOC_STRICT_SIZE", "1", 1);
                if (!getenv("DYLD_INSERT_LIBRARIES")) {
                        setenv("DYLD_INSERT_LIBRARIES", "/usr/lib/libgmalloc.dylib", 1);
                        setenv("MALLOC_STRICT_SIZE", "1", 1);
@@ -141,6 +136,13 @@ main(int argc, char *const *argv)
                        unsetenv("DYLD_INSERT_LIBRARIES");
                        unsetenv("MALLOC_STRICT_SIZE");
                }
                        unsetenv("DYLD_INSERT_LIBRARIES");
                        unsetenv("MALLOC_STRICT_SIZE");
                }
+       } else if (g_malloc_log_stacks) {
+               if (!getenv("MallocStackLogging")) {
+                       setenv("MallocStackLogging", "1", 1);
+                       execv(argv[0], argv);
+               } else {
+                       unsetenv("MallocStackLogging");
+               }
        }
 
        while ((ch = getopt(argc, argv, "s")) != -1) {
        }
 
        while ((ch = getopt(argc, argv, "s")) != -1) {
@@ -160,11 +162,11 @@ main(int argc, char *const *argv)
 
        launchd_runtime_init();
 
 
        launchd_runtime_init();
 
-       if( pid1_magic ) {
+       if (pid1_magic) {
                int cfd = -1;
                int cfd = -1;
-               if( launchd_assumes((cfd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) != -1) ) {
+               if (launchd_assumes((cfd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) != -1)) {
                        _fd(cfd);
                        _fd(cfd);
-                       if( !launchd_assumes((g_console = fdopen(cfd, "w")) != NULL) ) {
+                       if (!launchd_assumes((g_console = fdopen(cfd, "w")) != NULL)) {
                                close(cfd);
                        }
                }
                                close(cfd);
                        }
                }
@@ -182,14 +184,14 @@ main(int argc, char *const *argv)
                runtime_log_push();
                
                struct passwd *pwent = getpwuid(getuid());
                runtime_log_push();
                
                struct passwd *pwent = getpwuid(getuid());
-               if( pwent ) {
+               if (pwent) {
                        strlcpy(g_username, pwent->pw_name, sizeof(g_username) - 1);
                }
 
                snprintf(g_my_label, sizeof(g_my_label), "com.apple.launchd.peruser.%u", getuid());
                
                auditinfo_addr_t auinfo;
                        strlcpy(g_username, pwent->pw_name, sizeof(g_username) - 1);
                }
 
                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) ) {
+               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 = auinfo.ai_asid;
                        runtime_syslog(LOG_DEBUG, "Our audit session ID is %i", g_audit_session);
                }
@@ -199,22 +201,29 @@ main(int argc, char *const *argv)
                runtime_syslog(LOG_DEBUG, "Per-user launchd for UID %u (%s) has begun.", getuid(), g_username);
        }
 
                runtime_syslog(LOG_DEBUG, "Per-user launchd for UID %u (%s) has begun.", getuid(), g_username);
        }
 
-       if( pid1_magic ) {
+       if (pid1_magic) {
                runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** launchd[1] has started up. ***");
                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_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( g_verbose_boot ) {
+               if (g_verbose_boot) {
                        runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Verbose boot, will log to /dev/console. ***");
                }
 
                        runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Verbose boot, will log to /dev/console. ***");
                }
 
-               if( g_shutdown_debugging ) {
+               if (g_shutdown_debugging) {
                        runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Shutdown debugging is enabled. ***");
                }
 
                /* PID 1 doesn't have a flat namespace. */
                g_flat_mach_namespace = false;
                        runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Shutdown debugging is enabled. ***");
                }
 
                /* PID 1 doesn't have a flat namespace. */
                g_flat_mach_namespace = false;
+       } else {
+               if (g_use_gmalloc) {
+                       runtime_syslog(LOG_NOTICE, "*** Per-user launchd using libgmalloc. ***");
+               }
        }
 
        monitor_networking_state();
        }
 
        monitor_networking_state();
@@ -229,12 +238,12 @@ main(int argc, char *const *argv)
        #endif
        }
 
        #endif
        }
 
-       if( pid1_magic ) {
+       if (pid1_magic) {
                /* Start the update thread -- rdar://problem/5039559&6153301 */
                pthread_t t = NULL;
                int err = pthread_create(&t, NULL, update_thread, NULL);
                /* Start the update thread -- rdar://problem/5039559&6153301 */
                pthread_t t = NULL;
                int err = pthread_create(&t, NULL, update_thread, NULL);
-               launchd_assumes(err == 0);
-               launchd_assumes(pthread_detach(t) == 0);
+               (void)launchd_assumes(err == 0);
+               (void)launchd_assumes(pthread_detach(t) == 0);
        }
 
        jobmgr_init(sflag);
        }
 
        jobmgr_init(sflag);
@@ -253,14 +262,19 @@ handle_pid1_crashes_separately(void)
        fsa.sa_flags = SA_SIGINFO;
        sigemptyset(&fsa.sa_mask);
 
        fsa.sa_flags = SA_SIGINFO;
        sigemptyset(&fsa.sa_mask);
 
-       launchd_assumes(sigaction(SIGILL, &fsa, NULL) != -1);
-       launchd_assumes(sigaction(SIGFPE, &fsa, NULL) != -1);
-       launchd_assumes(sigaction(SIGBUS, &fsa, NULL) != -1);
-       launchd_assumes(sigaction(SIGSEGV, &fsa, NULL) != -1);
+       (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);
 }
 
 void *update_thread(void *nothing __attribute__((unused)))
 {
 }
 
 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);
        while( g_sync_frequency ) {
                sync();
                sleep(g_sync_frequency);
@@ -278,15 +292,15 @@ static __attribute__((unused)) typeof(sleep) *__junk_dyld_trick2 = sleep;
 static __attribute__((unused)) typeof(reboot) *__junk_dyld_trick3 = reboot;
 
 void
 static __attribute__((unused)) typeof(reboot) *__junk_dyld_trick3 = reboot;
 
 void
-do_pid1_crash_diagnosis_mode(void)
+do_pid1_crash_diagnosis_mode(const char *msg)
 {
 {
-       if( g_wsp ) {
+       if (g_wsp) {
                kill(g_wsp, SIGKILL);
                sleep(3);
                g_wsp = 0;
        }
 
                kill(g_wsp, SIGKILL);
                sleep(3);
                g_wsp = 0;
        }
 
-       while( g_shutdown_debugging && !do_pid1_crash_diagnosis_mode2() ) {
+       while (g_shutdown_debugging && !do_pid1_crash_diagnosis_mode2(msg)) {
                sleep(1);
        }
 }
                sleep(1);
        }
 }
@@ -298,48 +312,37 @@ basic_fork(void)
        pid_t p;
        
        switch ((p = fork())) {
        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:
-               #if 0
-                       /* If we attach with the debugger, the kernel reparenting could 
-                        * cause this to return prematurely.
-                        */
-                       waitpid(p, &wstatus, 0);
-               #else
-                       sleep(UINT_MAX);
-               #endif
-                       if (WIFEXITED(wstatus)) {
-                               if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) {
-                                       return 1;
-                               } else {
-                                       fprintf(stdout, "PID 1 copy: exit status: %d\n", WEXITSTATUS(wstatus));
-                               }
-                       } else {
-                               fprintf(stdout, "PID 1 copy: %s\n", strsignal(WTERMSIG(wstatus)));
-                       }
-                       return 1;
+       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));
+
+               fprintf(stdout, "PID 1 copy: exit status: %d\n", WEXITSTATUS(wstatus));
+
+               return 1;
        }
        
        return -1;
 }
 
 bool
        }
        
        return -1;
 }
 
 bool
-do_pid1_crash_diagnosis_mode2(void)
+do_pid1_crash_diagnosis_mode2(const char *msg)
 {
 {
-       if( basic_fork() == 0 ) {
+       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.
                 */
                /* Neuter our bootstrap port so that the shell doesn't try talking to us while
                 * we're blocked waiting on it.
                 */
-               if( g_console ) {
+               if (g_console) {
                        fflush(g_console);
                }
                task_set_bootstrap_port(mach_task_self(), MACH_PORT_NULL);
                        fflush(g_console);
                }
                task_set_bootstrap_port(mach_task_self(), MACH_PORT_NULL);
-               if( basic_fork() != 0 ) {
-                       if( g_console ) {
+               if (basic_fork() != 0) {
+                       if (g_console) {
                                fflush(g_console);
                        }
                        return true;
                                fflush(g_console);
                        }
                        return true;
@@ -359,8 +362,9 @@ do_pid1_crash_diagnosis_mode2(void)
        setenv("TERM", "vt100", 1);
        fprintf(stdout, "\n");
        fprintf(stdout, "Entering launchd PID 1 debugging mode...\n");
        setenv("TERM", "vt100", 1);
        fprintf(stdout, "\n");
        fprintf(stdout, "Entering launchd PID 1 debugging mode...\n");
-       fprintf(stdout, "The PID 1 launchd has crashed. It has fork(2)ed itself for debugging.\n");
-       fprintf(stdout, "To debug the main thread of PID 1:\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, "    gdb attach %d\n", getppid());
        fprintf(stdout, "To exit this shell and shut down:\n");
        fprintf(stdout, "    kill -9 1\n");
@@ -377,6 +381,7 @@ void
 fatal_signal_handler(int sig, siginfo_t *si, void *uap __attribute__((unused)))
 {
        const char *doom_why = "at instruction";
 fatal_signal_handler(int sig, siginfo_t *si, void *uap __attribute__((unused)))
 {
        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;
        char *sample_args[] = { "/usr/bin/sample", "1", "1", "-file", PID1_CRASH_LOGFILE, NULL };
        pid_t sample_p;
        int wstatus;
@@ -398,8 +403,6 @@ fatal_signal_handler(int sig, siginfo_t *si, void *uap __attribute__((unused)))
                break;
        }
 
                break;
        }
 
-       do_pid1_crash_diagnosis_mode();
-
        switch (sig) {
        default:
        case 0:
        switch (sig) {
        default:
        case 0:
@@ -409,8 +412,9 @@ fatal_signal_handler(int sig, siginfo_t *si, void *uap __attribute__((unused)))
                doom_why = "trying to read/write";
        case SIGILL:
        case SIGFPE:
                doom_why = "trying to read/write";
        case SIGILL:
        case SIGFPE:
-               runtime_syslog(LOG_EMERG, "We crashed %s: %p (sent by PID %u)", doom_why, crash_addr, crash_pid);
+               snprintf(msg, sizeof(msg), "%s: %p (%s sent by PID %u)", doom_why, crash_addr, strsignal(sig), crash_pid);
                sync();
                sync();
+               do_pid1_crash_diagnosis_mode(msg);
                sleep(3);
                reboot(0);
                break;
                sleep(3);
                reboot(0);
                break;
@@ -420,29 +424,27 @@ fatal_signal_handler(int sig, siginfo_t *si, void *uap __attribute__((unused)))
 void
 pid1_magic_init(void)
 {
 void
 pid1_magic_init(void)
 {
-       launchd_assumes(setsid() != -1);
-       launchd_assumes(chdir("/") != -1);
-       launchd_assumes(setlogin("root") != -1);
+       (void)launchd_assumes(setsid() != -1);
+       (void)launchd_assumes(chdir("/") != -1);
+       (void)launchd_assumes(setlogin("root") != -1);
        
        strcpy(g_my_label, "com.apple.launchd");
 
        
        strcpy(g_my_label, "com.apple.launchd");
 
-#if !TARGET_OS_EMBEDDED        
+#if !TARGET_OS_EMBEDDED
        auditinfo_addr_t auinfo = {
                .ai_termid = { .at_type = AU_IPv4 },
                .ai_asid = AU_ASSIGN_ASID,
                .ai_auid = AU_DEFAUDITID,
        auditinfo_addr_t auinfo = {
                .ai_termid = { .at_type = AU_IPv4 },
                .ai_asid = AU_ASSIGN_ASID,
                .ai_auid = AU_DEFAUDITID,
-               .ai_flags = sessionIsRoot,
+               .ai_flags = AU_SESSION_FLAG_IS_INITIAL,
        };
        
        };
        
-       if( !launchd_assumes(setaudit_addr(&auinfo, sizeof(auinfo)) != -1) ) {
+       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);
        }
 
                runtime_syslog(LOG_WARNING | LOG_CONSOLE, "Could not set audit session: %s.", strerror(errno));
                _exit(EXIT_FAILURE);
        }
 
-       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 = auinfo.ai_asid;
+       runtime_syslog(LOG_DEBUG, "Audit Session ID: %i", g_audit_session);
 
        g_audit_session_port = _audit_session_self();
 #endif
 
        g_audit_session_port = _audit_session_self();
 #endif
@@ -456,11 +458,11 @@ launchd_data_base_path(int db_type)
        static char result[PATH_MAX];
        static int last_db_type = -1;
        
        static char result[PATH_MAX];
        static int last_db_type = -1;
        
-       if( db_type == last_db_type ) {
+       if (db_type == last_db_type) {
                return result;
        }
        
                return result;
        }
        
-       switch( db_type ) {
+       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;
                case LAUNCHD_DB_TYPE_OVERRIDES  :
                        snprintf(result, sizeof(result), "%s/%s", g_launchd_database_dir, "overrides.plist");
                        last_db_type = db_type;
@@ -480,7 +482,7 @@ int
 _fd(int fd)
 {
        if (fd >= 0) {
 _fd(int fd)
 {
        if (fd >= 0) {
-               launchd_assumes(fcntl(fd, F_SETFD, 1) != -1);
+               (void)launchd_assumes(fcntl(fd, F_SETFD, 1) != -1);
        }
        return fd;
 }
        }
        return fd;
 }
@@ -498,7 +500,7 @@ launchd_shutdown(void)
 
        shutdown_in_progress = true;
 
 
        shutdown_in_progress = true;
 
-       if( pid1_magic || g_log_per_user_shutdown ) {
+       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
                /*
                 * When this changes to a more sustainable API, update this:
                 * http://howto.apple.com/db.cgi?Debugging_Apps_Non-Responsive_At_Shutdown
@@ -516,8 +518,8 @@ launchd_shutdown(void)
        launchd_assert(jobmgr_shutdown(root_jobmgr) != NULL);
 
 #if HAVE_LIBAUDITD
        launchd_assert(jobmgr_shutdown(root_jobmgr) != NULL);
 
 #if HAVE_LIBAUDITD
-       if( pid1_magic ) {
-               launchd_assumes(audit_quick_stop() == 0);
+       if (pid1_magic) {
+               (void)launchd_assumes(audit_quick_stop() == 0);
        }
 #endif
 }
        }
 #endif
 }
@@ -539,15 +541,19 @@ launchd_single_user(void)
 void
 launchd_SessionCreate(void)
 {
 void
 launchd_SessionCreate(void)
 {
-#if HAVE_SECURITY
-       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));
        }
 #endif
 }
        }
 #endif
 }
@@ -558,13 +564,13 @@ testfd_or_openfd(int fd, const char *path, int flags)
        int tmpfd;
 
        if (-1 != (tmpfd = dup(fd))) {
        int tmpfd;
 
        if (-1 != (tmpfd = dup(fd))) {
-               launchd_assumes(runtime_close(tmpfd) == 0);
+               (void)launchd_assumes(runtime_close(tmpfd) == 0);
        } else {
                if (-1 == (tmpfd = open(path, flags | O_NOCTTY, DEFFILEMODE))) {
                        runtime_syslog(LOG_ERR, "open(\"%s\", ...): %m", path);
                } else if (tmpfd != fd) {
        } else {
                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(runtime_close(tmpfd) == 0);
+                       (void)launchd_assumes(dup2(tmpfd, fd) != -1);
+                       (void)launchd_assumes(runtime_close(tmpfd) == 0);
                }
        }
 }
                }
        }
 }
@@ -579,7 +585,7 @@ get_network_state(void)
        /* Workaround 4978696: getifaddrs() reports false ENOMEM */
        while ((r = getifaddrs(&ifa)) == -1 && errno == ENOMEM) {
                runtime_syslog(LOG_DEBUG, "Worked around bug: 4978696");
        /* Workaround 4978696: getifaddrs() reports false ENOMEM */
        while ((r = getifaddrs(&ifa)) == -1 && errno == ENOMEM) {
                runtime_syslog(LOG_DEBUG, "Worked around bug: 4978696");
-               launchd_assumes(sched_yield() != -1);
+               (void)launchd_assumes(sched_yield() != -1);
        }
 
        if (!launchd_assumes(r != -1)) {
        }
 
        if (!launchd_assumes(r != -1)) {
@@ -626,7 +632,7 @@ monitor_networking_state(void)
                return;
        }
 
                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
 }
 
 void
@@ -635,7 +641,7 @@ pfsystem_callback(void *obj __attribute__((unused)), struct kevent *kev)
        bool new_networking_state;
        char buf[1024];
 
        bool new_networking_state;
        char buf[1024];
 
-       launchd_assumes(read((int)kev->ident, &buf, sizeof(buf)) != -1);
+       (void)launchd_assumes(read((int)kev->ident, &buf, sizeof(buf)) != -1);
 
        new_networking_state = get_network_state();
 
 
        new_networking_state = get_network_state();
 
index a8a0c9297822defe472b69a19e3cefefb8a66e12..595df1195c7e0253dba5a106e38fb653a13a63a4 100644 (file)
@@ -32,7 +32,6 @@ struct conncb;
 extern bool shutdown_in_progress;
 extern bool fake_shutdown_in_progress;
 extern bool network_up;
 extern bool shutdown_in_progress;
 extern bool fake_shutdown_in_progress;
 extern bool network_up;
-extern bool g_force_old_kill_path;
 extern bool g_simulate_pid1_crash;
 extern FILE *g_console;
 extern char g_launchd_database_dir[PATH_MAX];
 extern bool g_simulate_pid1_crash;
 extern FILE *g_console;
 extern char g_launchd_database_dir[PATH_MAX];
index 6d201206ffbf58ebc719ded8e433218efabd1a1f..068f56a1073f56e1391626758a0ace028c646704 100644 (file)
@@ -343,18 +343,6 @@ When a job dies,
 .Nm launchd
 kills any remaining processes with the same process group ID as the job.
 Setting this key to true disables that behavior.
 .Nm launchd
 kills any remaining processes with the same process group ID as the job.
 Setting this key to true disables that behavior.
-.It Sy HopefullyExitsFirst <boolean>
-This optional key causes programs to exit earlier during system shutdown.
-This key exists because some jobs do more than flush buffers and exit like
-they're supposed to. The use of this key should be considered a
-temporary solution until the software can be changed to only flush dirty buffers
-and then exit.
-.It Sy HopefullyExitsLast <boolean>
-This optional key causes programs to exit later during system shutdown. This
-key exists because some jobs don't reference count their clients, and therefore
-do not know when it is safe to exit. The use of this key should be considered a
-temporary solution until the software can be changed to properly reference
-count clients.
 .It Sy LowPriorityIO <boolean>
 This optional key specifies whether the kernel should consider this daemon to be low priority when doing file system I/O.
 .It Sy LaunchOnlyOnce <boolean>
 .It Sy LowPriorityIO <boolean>
 This optional key specifies whether the kernel should consider this daemon to be low priority when doing file system I/O.
 .It Sy LaunchOnlyOnce <boolean>
index 6daf059fe47d49ab5ab4c2f6215bbbb44112c8a1..c04a496df5b75fe113d39197718b73621aaf4181 100644 (file)
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
-static const char *const __rcs_file_version__ = "$Revision: 24498 $";
+static const char *const __rcs_file_version__ = "$Revision: 24984 $";
 
 #include "config.h"
 #include "launchd_core_logic.h"
 
 #include "config.h"
 #include "launchd_core_logic.h"
+#include "launch_internal.h"
+#include "launchd_helper.h"
 
 #include <TargetConditionals.h>
 #include <mach/mach.h>
 
 #include <TargetConditionals.h>
 #include <mach/mach.h>
@@ -75,10 +77,14 @@ static const char *const __rcs_file_version__ = "$Revision: 24498 $";
 #include <string.h>
 #include <ctype.h>
 #include <glob.h>
 #include <string.h>
 #include <ctype.h>
 #include <glob.h>
+#include <System/sys/spawn.h>
 #include <spawn.h>
 #include <spawn.h>
+#include <time.h>
+
 #include <libproc.h>
 #include <malloc/malloc.h>
 #include <pthread.h>
 #include <libproc.h>
 #include <malloc/malloc.h>
 #include <pthread.h>
+#include <libproc.h>
 #if HAVE_SANDBOX
 #define __APPLE_API_PRIVATE
 #include <sandbox.h>
 #if HAVE_SANDBOX
 #define __APPLE_API_PRIVATE
 #include <sandbox.h>
@@ -92,6 +98,7 @@ static const char *const __rcs_file_version__ = "$Revision: 24498 $";
 /* To make my life easier. */
 typedef struct jetsam_priority_entry {
        pid_t pid;
 /* To make my life easier. */
 typedef struct jetsam_priority_entry {
        pid_t pid;
+       uint32_t priority;
        uint32_t flags;
        int32_t hiwat_pages;
        int32_t hiwat_reserved1;
        uint32_t flags;
        int32_t hiwat_pages;
        int32_t hiwat_reserved1;
@@ -123,20 +130,32 @@ enum {
 #include "protocol_job_reply.h"
 #include "protocol_job_forward.h"
 #include "mach_excServer.h"
 #include "protocol_job_reply.h"
 #include "protocol_job_forward.h"
 #include "mach_excServer.h"
+#if !TARGET_OS_EMBEDDED
+#include "domainServer.h"
+#include "init.h"
+#endif
+#include "eventsServer.h"
 
 
-/*
- * LAUNCHD_SAMPLE_TIMEOUT
- *   If the job hasn't exited in the given number of seconds after sending
- *   it a SIGTERM, start sampling it.
- * LAUNCHD_DEFAULT_EXIT_TIMEOUT
+#ifndef POSIX_SPAWN_OSX_TALAPP_START
+#define POSIX_SPAWN_OSX_TALAPP_START 0x0400
+#endif
+
+#ifndef POSIX_SPAWN_OSX_WIDGET_START
+#define POSIX_SPAWN_OSX_WIDGET_START 0x0800
+#endif
+
+#ifndef POSIX_SPAWN_IOS_APP_START
+#define POSIX_SPAWN_IOS_APP_START 0x1000
+#endif
+
+/* LAUNCHD_DEFAULT_EXIT_TIMEOUT
  *   If the job hasn't exited in the given number of seconds after sending
  *   it a SIGTERM, SIGKILL it. Can be overriden in the job plist.
  */
 #define LAUNCHD_MIN_JOB_RUN_TIME               10
  *   If the job hasn't exited in the given number of seconds after sending
  *   it a SIGTERM, SIGKILL it. Can be overriden in the job plist.
  */
 #define LAUNCHD_MIN_JOB_RUN_TIME               10
-#define LAUNCHD_SAMPLE_TIMEOUT                 2
 #define LAUNCHD_DEFAULT_EXIT_TIMEOUT   20
 #define LAUNCHD_DEFAULT_EXIT_TIMEOUT   20
-#define LAUNCHD_SIGKILL_TIMER                  5
-#define LAUNCHD_CLEAN_KILL_TIMER               1
+#define LAUNCHD_SIGKILL_TIMER                  2
+#define LAUNCHD_LOG_FAILED_EXEC_FREQ   10
 
 #define SHUTDOWN_LOG_DIR "/var/log/shutdown"
 
 
 #define SHUTDOWN_LOG_DIR "/var/log/shutdown"
 
@@ -156,39 +175,34 @@ struct waiting_for_removal {
 static bool waiting4removal_new(job_t j, mach_port_t rp);
 static void waiting4removal_delete(job_t j, struct waiting_for_removal *w4r);
 
 static bool waiting4removal_new(job_t j, mach_port_t rp);
 static void waiting4removal_delete(job_t j, struct waiting_for_removal *w4r);
 
-struct waiting_for_exit {
-       LIST_ENTRY(waiting_for_exit) sle;
-       mach_port_t rp;
-       bool legacy;
-};
-
-static bool waiting4exit_new(job_t j, mach_port_t rp, bool legacy);
-static void waiting4exit_delete(job_t j, struct waiting_for_exit *w4e);
-
 struct machservice {
        SLIST_ENTRY(machservice) sle;
        SLIST_ENTRY(machservice) special_port_sle;
        LIST_ENTRY(machservice) name_hash_sle;
        LIST_ENTRY(machservice) port_hash_sle;
 struct machservice {
        SLIST_ENTRY(machservice) sle;
        SLIST_ENTRY(machservice) special_port_sle;
        LIST_ENTRY(machservice) name_hash_sle;
        LIST_ENTRY(machservice) port_hash_sle;
+       struct machservice *alias;
        job_t                           job;
        unsigned int            gen_num;
        mach_port_name_t        port;
        job_t                           job;
        unsigned int            gen_num;
        mach_port_name_t        port;
-       unsigned int            isActive                                        :1,
-                                               reset                                           :1,
-                                               recv                                            :1,
-                                               hide                                            :1,
-                                               kUNCServer                                      :1,
-                                               per_user_hack                           :1,
-                                               debug_on_close                          :1,
-                                               per_pid                                         :1,
-                                               delete_on_destruction           :1,
-                                               drain_one_on_crash                      :1,
-                                               drain_all_on_crash                      :1,
-                                               /* Don't let the size of this field to get too small. It has to be large enough
-                                                * to represent the reasonable range of special port numbers.
-                                                */
-                                               special_port_num                        :20;
-       
+       unsigned int
+               isActive                                        :1,
+               reset                                           :1,
+               recv                                            :1,
+               hide                                            :1,
+               kUNCServer                                      :1,
+               per_user_hack                           :1,
+               debug_on_close                          :1,
+               per_pid                                         :1,
+               delete_on_destruction           :1,
+               drain_one_on_crash                      :1,
+               drain_all_on_crash                      :1,
+               event_update_port                       :1, /* The job which owns this port is the event monitor. */
+               upfront                                         :1, /* This service was declared in the plist. */
+               event_channel                           :1, /* The job is to receive events on this channel. */
+               /* Don't let the size of this field to get too small. It has to be large enough
+                * to represent the reasonable range of special port numbers.
+                */
+               special_port_num                        :18;
        const char              name[0];
 };
 
        const char              name[0];
 };
 
@@ -203,6 +217,9 @@ static void machservice_setup(launch_data_t obj, const char *key, void *context)
 static void machservice_setup_options(launch_data_t obj, const char *key, void *context);
 static void machservice_resetport(job_t j, struct machservice *ms);
 static struct machservice *machservice_new(job_t j, const char *name, mach_port_t *serviceport, bool pid_local);
 static void machservice_setup_options(launch_data_t obj, const char *key, void *context);
 static void machservice_resetport(job_t j, struct machservice *ms);
 static struct machservice *machservice_new(job_t j, const char *name, mach_port_t *serviceport, bool pid_local);
+#ifndef __LAUNCH_DISABLE_XPC_SUPPORT__
+static struct machservice *machservice_new_alias(job_t aj, struct machservice *orig);
+#endif
 static void machservice_ignore(job_t j, struct machservice *ms);
 static void machservice_watch(job_t j, struct machservice *ms);
 static void machservice_delete(job_t j, struct machservice *, bool port_died);
 static void machservice_ignore(job_t j, struct machservice *ms);
 static void machservice_watch(job_t j, struct machservice *ms);
 static void machservice_delete(job_t j, struct machservice *, bool port_died);
@@ -214,6 +231,7 @@ static bool machservice_active(struct machservice *);
 static const char *machservice_name(struct machservice *);
 static bootstrap_status_t machservice_status(struct machservice *);
 void machservice_drain_port(struct machservice *);
 static const char *machservice_name(struct machservice *);
 static bootstrap_status_t machservice_status(struct machservice *);
 void machservice_drain_port(struct machservice *);
+static struct machservice *xpc_events_find_channel(job_t j, event_name_t stream, mach_port_t *p);
 
 struct socketgroup {
        SLIST_ENTRY(socketgroup) sle;
 
 struct socketgroup {
        SLIST_ENTRY(socketgroup) sle;
@@ -286,6 +304,8 @@ typedef enum {
        NETWORK_DOWN,
        SUCCESSFUL_EXIT,
        FAILED_EXIT,
        NETWORK_DOWN,
        SUCCESSFUL_EXIT,
        FAILED_EXIT,
+       CRASHED,
+       DID_NOT_CRASH,
        PATH_EXISTS,
        PATH_MISSING,
        OTHER_JOB_ENABLED,
        PATH_EXISTS,
        PATH_MISSING,
        OTHER_JOB_ENABLED,
@@ -302,6 +322,7 @@ struct semaphoreitem {
        semaphore_reason_t why;
        bool watching_parent;
        int fd;
        semaphore_reason_t why;
        bool watching_parent;
        int fd;
+       
        union {
                const char what[0];
                char what_init[0];
        union {
                const char what[0];
                char what_init[0];
@@ -323,63 +344,121 @@ static void semaphoreitem_watch(job_t j, struct semaphoreitem *si);
 static void semaphoreitem_ignore(job_t j, struct semaphoreitem *si);
 static void semaphoreitem_runtime_mod_ref(struct semaphoreitem *si, bool add);
 
 static void semaphoreitem_ignore(job_t j, struct semaphoreitem *si);
 static void semaphoreitem_runtime_mod_ref(struct semaphoreitem *si, bool add);
 
-#define ACTIVE_JOB_HASH_SIZE   32
-#define ACTIVE_JOB_HASH(x)     (IS_POWER_OF_TWO(ACTIVE_JOB_HASH_SIZE) ? (x & (ACTIVE_JOB_HASH_SIZE - 1)) : (x % ACTIVE_JOB_HASH_SIZE))
-
-#define MACHSERVICE_HASH_SIZE  37
+struct externalevent {
+       LIST_ENTRY(externalevent) sys_le;
+       LIST_ENTRY(externalevent) job_le;
+       struct eventsystem *sys;
+       
+       uint64_t id;
+       job_t job;
+       bool state;
+       bool wanted_state;
+       launch_data_t event;
+       
+       char name[0];
+};
 
 
-enum {
-       JOBMGR_PHASE_HOPEFULLY_EXITS_FIRST,
-       JOBMGR_PHASE_NORMAL,
-       JOBMGR_PHASE_HOPEFULLY_EXITS_LAST,
-       JOBMGR_PHASE_LAST,
+struct externalevent_iter_ctx {
+       job_t j;
+       struct eventsystem *sys;
 };
 
 };
 
-static char *s_phases[JOBMGR_PHASE_LAST + 1] = {
-       "HopefullyExitsFirst",
-       "Normal",
-       "HopefullyExitsLast",
-       "Finalized",
+static bool externalevent_new(job_t j, struct eventsystem *sys, char *evname, launch_data_t event);
+static void externalevent_delete(struct externalevent *ee);
+static void externalevent_setup(launch_data_t obj, const char *key, void *context);
+static struct externalevent *externalevent_find(const char *sysname, uint64_t id);
+
+struct eventsystem {
+       LIST_ENTRY(eventsystem) global_le;
+       LIST_HEAD(, externalevent) events;
+       uint64_t curid;
+       bool has_updates;
+       char name[0];
 };
 
 };
 
+static struct eventsystem *eventsystem_new(const char *name);
+static void eventsystem_delete(struct eventsystem *sys);
+static void eventsystem_setup(launch_data_t obj, const char *key, void *context);
+static struct eventsystem *eventsystem_find(const char *name);
+static void eventsystem_ping(void);
+
+#define ACTIVE_JOB_HASH_SIZE   32
+#define ACTIVE_JOB_HASH(x)     (IS_POWER_OF_TWO(ACTIVE_JOB_HASH_SIZE) ? (x & (ACTIVE_JOB_HASH_SIZE - 1)) : (x % ACTIVE_JOB_HASH_SIZE))
+
+#define MACHSERVICE_HASH_SIZE  37
+
+#define LABEL_HASH_SIZE 53
 struct jobmgr_s {
        kq_callback kqjobmgr_callback;
 struct jobmgr_s {
        kq_callback kqjobmgr_callback;
+       LIST_ENTRY(jobmgr_s) xpc_le;
        SLIST_ENTRY(jobmgr_s) sle;
        SLIST_HEAD(, jobmgr_s) submgrs;
        LIST_HEAD(, job_s) jobs;
        LIST_HEAD(, job_s) jetsam_jobs;
        SLIST_ENTRY(jobmgr_s) sle;
        SLIST_HEAD(, jobmgr_s) submgrs;
        LIST_HEAD(, job_s) jobs;
        LIST_HEAD(, job_s) jetsam_jobs;
+       
+       /* For legacy reasons, we keep all job labels that are imported in the
+        * root job manager's label hash. If a job manager is an XPC domain, then
+        * it gets its own label hash that is separate from the "global" one
+        * stored in the root job manager.
+        */
+       LIST_HEAD(, job_s) label_hash[LABEL_HASH_SIZE];
        LIST_HEAD(, job_s) active_jobs[ACTIVE_JOB_HASH_SIZE];
        LIST_HEAD(, machservice) ms_hash[MACHSERVICE_HASH_SIZE];
        LIST_HEAD(, job_s) global_env_jobs;
        LIST_HEAD(, job_s) active_jobs[ACTIVE_JOB_HASH_SIZE];
        LIST_HEAD(, machservice) ms_hash[MACHSERVICE_HASH_SIZE];
        LIST_HEAD(, job_s) global_env_jobs;
-       STAILQ_HEAD(, job_s) pending_samples;
        mach_port_t jm_port;
        mach_port_t req_port;
        mach_port_t jm_port;
        mach_port_t req_port;
-       mach_port_t init_audit_session;
        jobmgr_t parentmgr;
        int reboot_flags;
        jobmgr_t parentmgr;
        int reboot_flags;
-       int shutdown_phase;
+       time_t shutdown_time;
        unsigned int global_on_demand_cnt;
        unsigned int global_on_demand_cnt;
-       unsigned int hopefully_first_cnt;
        unsigned int normal_active_cnt;
        unsigned int jetsam_jobs_cnt;
        unsigned int normal_active_cnt;
        unsigned int jetsam_jobs_cnt;
-       unsigned int    shutting_down                                   :1,
-                                       session_initialized                             :1, 
-                                       killed_hopefully_first_jobs             :1,
-                                       killed_normal_jobs                              :1,
-                                       killed_hopefully_last_jobs              :1,
-                                       killed_stray_jobs                               :1;
-       char sample_log_file[PATH_MAX];
+       unsigned int 
+               shutting_down                                   :1,
+               session_initialized                             :1, 
+               killed_stray_jobs                               :1,
+               monitor_shutdown                                :1,
+               shutdown_jobs_dirtied                   :1,
+               shutdown_jobs_cleaned                   :1,
+               xpc_singleton                                   :1;
        uint32_t properties;
        uint32_t properties;
+       /* XPC-specific properties. */
+       char owner[MAXCOMLEN];
+       char *shortdesc;
+       mach_port_t req_bsport;
+       mach_port_t req_excport;
+       mach_port_t req_asport;
+       pid_t req_pid;
+       uid_t req_euid;
+       gid_t req_egid;
+       au_asid_t req_asid;
+       vm_offset_t req_ctx;
+       mach_msg_type_number_t req_ctx_sz;
+       mach_port_t req_rport;
+       kern_return_t error;
        union {
                const char name[0];
                char name_init[0];
        };
 };
 
        union {
                const char name[0];
                char name_init[0];
        };
 };
 
+/* Global XPC domains. */
+#ifndef __LAUNCH_DISABLE_XPC_SUPPORT__
+static jobmgr_t _s_xpc_system_domain;
+static LIST_HEAD(, jobmgr_s) _s_xpc_user_domains;
+static LIST_HEAD(, jobmgr_s) _s_xpc_session_domains;
+#endif
+
 #define jobmgr_assumes(jm, e)  \
        (unlikely(!(e)) ? jobmgr_log_bug(jm, __LINE__), false : true)
 
 #define jobmgr_assumes(jm, e)  \
        (unlikely(!(e)) ? jobmgr_log_bug(jm, __LINE__), false : true)
 
-static jobmgr_t jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bool sflag, const char *name, bool no_init, mach_port_t session_port);
+static jobmgr_t jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bool sflag, const char *name, bool no_init, mach_port_t asport);
+#ifndef __LAUNCH_DISABLE_XPC_SUPPORT__
+static jobmgr_t jobmgr_new_xpc_singleton_domain(jobmgr_t jm, name_t name);
+static jobmgr_t jobmgr_find_xpc_per_user_domain(jobmgr_t jm, uid_t uid);
+static jobmgr_t jobmgr_find_xpc_per_session_domain(jobmgr_t jm, au_asid_t asid);
+static job_t xpc_domain_import_service(jobmgr_t jm, launch_data_t pload);
+#endif
 static job_t jobmgr_import2(jobmgr_t jm, launch_data_t pload);
 static jobmgr_t jobmgr_parent(jobmgr_t jm);
 static jobmgr_t jobmgr_do_garbage_collection(jobmgr_t jm);
 static job_t jobmgr_import2(jobmgr_t jm, launch_data_t pload);
 static jobmgr_t jobmgr_parent(jobmgr_t jm);
 static jobmgr_t jobmgr_do_garbage_collection(jobmgr_t jm);
@@ -389,13 +468,12 @@ static void jobmgr_log_stray_children(jobmgr_t jm, bool kill_strays);
 static void jobmgr_kill_stray_children(jobmgr_t jm, pid_t *p, size_t np);
 static void jobmgr_remove(jobmgr_t jm);
 static void jobmgr_dispatch_all(jobmgr_t jm, bool newmounthack);
 static void jobmgr_kill_stray_children(jobmgr_t jm, pid_t *p, size_t np);
 static void jobmgr_remove(jobmgr_t jm);
 static void jobmgr_dispatch_all(jobmgr_t jm, bool newmounthack);
-static void jobmgr_dequeue_next_sample(jobmgr_t jm);
 static job_t jobmgr_init_session(jobmgr_t jm, const char *session_type, bool sflag);
 static job_t jobmgr_find_by_pid_deep(jobmgr_t jm, pid_t p, bool anon_okay);
 static job_t jobmgr_find_by_pid(jobmgr_t jm, pid_t p, bool create_anon);
 static jobmgr_t jobmgr_find_by_name(jobmgr_t jm, const char *where);
 static job_t job_mig_intran2(jobmgr_t jm, mach_port_t mport, pid_t upid);
 static job_t jobmgr_init_session(jobmgr_t jm, const char *session_type, bool sflag);
 static job_t jobmgr_find_by_pid_deep(jobmgr_t jm, pid_t p, bool anon_okay);
 static job_t jobmgr_find_by_pid(jobmgr_t jm, pid_t p, bool create_anon);
 static jobmgr_t jobmgr_find_by_name(jobmgr_t jm, const char *where);
 static job_t job_mig_intran2(jobmgr_t jm, mach_port_t mport, pid_t upid);
-static job_t jobmgr_lookup_per_user_context_internal(job_t j, uid_t which_user, bool dispatch, mach_port_t *mp);
+static job_t jobmgr_lookup_per_user_context_internal(job_t j, uid_t which_user, mach_port_t *mp);
 static void job_export_all2(jobmgr_t jm, launch_data_t where);
 static void jobmgr_callback(void *obj, struct kevent *kev);
 static void jobmgr_setup_env_from_other_jobs(jobmgr_t jm);
 static void job_export_all2(jobmgr_t jm, launch_data_t where);
 static void jobmgr_callback(void *obj, struct kevent *kev);
 static void jobmgr_setup_env_from_other_jobs(jobmgr_t jm);
@@ -408,6 +486,7 @@ static void jobmgr_log_bug(jobmgr_t jm, unsigned int line);
 
 #define AUTO_PICK_LEGACY_LABEL (const char *)(~0)
 #define AUTO_PICK_ANONYMOUS_LABEL (const char *)(~1)
 
 #define AUTO_PICK_LEGACY_LABEL (const char *)(~0)
 #define AUTO_PICK_ANONYMOUS_LABEL (const char *)(~1)
+#define AUTO_PICK_XPC_LABEL (const char *)(~2)
 
 struct suspended_peruser {
        LIST_ENTRY(suspended_peruser) sle;
 
 struct suspended_peruser {
        LIST_ENTRY(suspended_peruser) sle;
@@ -417,15 +496,17 @@ struct suspended_peruser {
 struct job_s {
        kq_callback kqjob_callback;     /* MUST be first element of this structure for benefit of launchd's run loop. */
        LIST_ENTRY(job_s) sle;
 struct job_s {
        kq_callback kqjob_callback;     /* MUST be first element of this structure for benefit of launchd's run loop. */
        LIST_ENTRY(job_s) sle;
+       LIST_ENTRY(job_s) subjob_sle;
        LIST_ENTRY(job_s) needing_session_sle;
        LIST_ENTRY(job_s) jetsam_sle;
        LIST_ENTRY(job_s) pid_hash_sle;
        LIST_ENTRY(job_s) label_hash_sle;
        LIST_ENTRY(job_s) global_env_sle;
        LIST_ENTRY(job_s) needing_session_sle;
        LIST_ENTRY(job_s) jetsam_sle;
        LIST_ENTRY(job_s) pid_hash_sle;
        LIST_ENTRY(job_s) label_hash_sle;
        LIST_ENTRY(job_s) global_env_sle;
-       STAILQ_ENTRY(job_s) pending_samples_sle;
        SLIST_ENTRY(job_s) curious_jobs_sle;
        LIST_HEAD(, suspended_peruser) suspended_perusers;
        LIST_HEAD(, waiting_for_exit) exit_watchers;
        SLIST_ENTRY(job_s) curious_jobs_sle;
        LIST_HEAD(, suspended_peruser) suspended_perusers;
        LIST_HEAD(, waiting_for_exit) exit_watchers;
+       LIST_HEAD(, job_s) subjobs;
+       LIST_HEAD(, externalevent) events;
        SLIST_HEAD(, socketgroup) sockets;
        SLIST_HEAD(, calendarinterval) cal_intervals;
        SLIST_HEAD(, envitem) global_env;
        SLIST_HEAD(, socketgroup) sockets;
        SLIST_HEAD(, calendarinterval) cal_intervals;
        SLIST_HEAD(, envitem) global_env;
@@ -434,11 +515,14 @@ struct job_s {
        SLIST_HEAD(, machservice) machservices;
        SLIST_HEAD(, semaphoreitem) semaphores;
        SLIST_HEAD(, waiting_for_removal) removal_watchers;
        SLIST_HEAD(, machservice) machservices;
        SLIST_HEAD(, semaphoreitem) semaphores;
        SLIST_HEAD(, waiting_for_removal) removal_watchers;
+       job_t alias;
        struct rusage ru;
        cpu_type_t *j_binpref;
        size_t j_binpref_cnt;
        mach_port_t j_port;
        struct rusage ru;
        cpu_type_t *j_binpref;
        size_t j_binpref_cnt;
        mach_port_t j_port;
-       mach_port_t wait_reply_port; /* we probably should switch to a list of waiters */
+       mach_port_t exit_status_dest;
+       mach_port_t exit_status_port;
+       mach_port_t spawn_reply_port;
        uid_t mach_uid;
        jobmgr_t mgr;
        size_t argc;
        uid_t mach_uid;
        jobmgr_t mgr;
        size_t argc;
@@ -470,8 +554,10 @@ struct job_s {
        int log_redirect_fd;
        int nice;
        int stdout_err_fd;
        int log_redirect_fd;
        int nice;
        int stdout_err_fd;
+       uint32_t pstype;
        int32_t jetsam_priority;
        int32_t jetsam_memlimit;
        int32_t jetsam_priority;
        int32_t jetsam_memlimit;
+       int32_t jetsam_seq;
        int32_t main_thread_priority;
        uint32_t timeout;
        uint32_t exit_timeout;
        int32_t main_thread_priority;
        uint32_t timeout;
        uint32_t exit_timeout;
@@ -480,6 +566,8 @@ struct job_s {
        uint32_t min_run_time;
        uint32_t start_interval;
        uint32_t peruser_suspend_count; /* The number of jobs that have disabled this per-user launchd. */
        uint32_t min_run_time;
        uint32_t start_interval;
        uint32_t peruser_suspend_count; /* The number of jobs that have disabled this per-user launchd. */
+       uuid_t instance_id;
+       uint32_t fail_cnt;
 #if 0
        /* someday ... */
        enum {
 #if 0
        /* someday ... */
        enum {
@@ -489,76 +577,81 @@ struct job_s {
                J_TYPE_INETD,
        } j_type;
 #endif
                J_TYPE_INETD,
        } j_type;
 #endif
-       bool    debug                                           :1,     /* man launchd.plist --> Debug */
-                   ondemand                                    :1,     /* man launchd.plist --> KeepAlive == false */
-                   session_create                              :1,     /* man launchd.plist --> SessionCreate */
-                   low_pri_io                                  :1,     /* man launchd.plist --> LowPriorityIO */
-                   no_init_groups                              :1,     /* man launchd.plist --> InitGroups */
-                   priv_port_has_senders               :1,     /* a legacy mach_init concept to make bootstrap_create_server/service() work */
-                   importing_global_env                :1,     /* a hack during job importing */
-                   importing_hard_limits               :1,     /* a hack during job importing */
-                   setmask                                             :1,     /* man launchd.plist --> Umask */
-                   anonymous                                   :1,     /* a process that launchd knows about, but isn't managed by launchd */
-                   checkedin                                   :1,     /* a legacy mach_init concept to detect sick jobs */
-                   legacy_mach_job                             :1,     /* a job created via bootstrap_create_server() */
-                   legacy_LS_job                               :1,     /* a job created via spawn_via_launchd() */
-                   inetcompat                                  :1,     /* a legacy job that wants inetd compatible semantics */
-                   inetcompat_wait                             :1,     /* a twist on inetd compatibility */
-                   start_pending                               :1,     /* an event fired and the job should start, but not necessarily right away */
-                   globargv                                    :1,     /* man launchd.plist --> EnableGlobbing */
-                   wait4debugger                               :1,     /* man launchd.plist --> WaitForDebugger */
-                       wait4debugger_oneshot           :1, /* One-shot WaitForDebugger. */
-                   internal_exc_handler                :1,     /* MachExceptionHandler == true */
-                   stall_before_exec                   :1,     /* a hack to support an option of spawn_via_launchd() */
-                   only_once                                   :1,     /* man launchd.plist --> LaunchOnlyOnce. Note: 5465184 Rename this to "HopefullyNeverExits" */
-                   currently_ignored                   :1,     /* Make job_ignore() / job_watch() work. If these calls were balanced, then this wouldn't be necessarily. */
-                   forced_peers_to_demand_mode :1,     /* A job that forced all other jobs to be temporarily launch-on-demand */
-                   setnice                                             :1,     /* man launchd.plist --> Nice */
-                   hopefully_exits_last                :1,     /* man launchd.plist --> HopefullyExitsLast */
-                   removal_pending                             :1,     /* a job was asked to be unloaded/removed while running, we'll remove it after it exits */
-                   sent_sigkill                                :1,     /* job_kill() was called */
-                   sampling_complete                   :1,     /* job_force_sampletool() was called (or is disabled) */
-                   debug_before_kill                   :1,     /* enter the kernel debugger before killing a job */
-                   weird_bootstrap                             :1,     /* a hack that launchd+launchctl use during jobmgr_t creation */
-                   start_on_mount                              :1,     /* man launchd.plist --> StartOnMount */
-                   per_user                                    :1,     /* This job is a per-user launchd managed by the PID 1 launchd */
-                   hopefully_exits_first               :1,     /* man launchd.plist --> HopefullyExitsFirst */
-                   deny_unknown_mslookups              :1,     /* A flag for changing the behavior of bootstrap_look_up() */
-                   unload_at_mig_return                :1,     /* A job thoroughly confused launchd. We need to unload it ASAP */
-                   abandon_pg                                  :1,     /* man launchd.plist --> AbandonProcessGroup */
-                       ignore_pg_at_shutdown           :1, /* During shutdown, do not send SIGTERM to stray processes in the process group of this job. */
-               poll_for_vfs_changes            :1,     /* a hack to work around the fact that kqueues don't work on all filesystems */
-               deny_job_creation                       :1,     /* Don't let this job create new 'job_t' objects in launchd */
-               kill_via_shmem                          :1,     /* man launchd.plist --> EnableTransactions */
-               sent_kill_via_shmem                     :1,     /* We need to 'kill_via_shmem' once-and-only-once */
-                       clean_kill                                      :1, /* The job was sent SIGKILL because it was clean. */
-                       pending_sample                          :1, /* This job needs to be sampled for some reason. */
-                       kill_after_sample                       :1, /* The job is to be killed after sampling. */
-                       is_being_sampled                        :1, /* We've spawned a sample tool to sample the job. */
-                       reap_after_trace                        :1,     /* The job exited before sample did, so we should reap it after sample is done. */
-                       nosy                                            :1, /* The job has an OtherJobEnabled KeepAlive criterion. */
-                       crashed                                         :1, /* The job is the default Mach exception handler, and it crashed. */
-                       reaped                                          :1, /* We've received NOTE_EXIT for the job. */
-                       stopped                                         :1, /* job_stop() was called. */
-                       jetsam_frontmost                        :1, /* The job is considered "frontmost" by Jetsam. */
-                       needs_kickoff                           :1, /* The job is to be kept alive continuously, but it must be initially kicked off. */
-                       is_bootstrapper                         :1, /* The job is a bootstrapper. */
-                       has_console                                     :1, /* The job owns the console. */
-                       clean_exit_timer_expired        :1, /* The job was clean, received SIGKILL and failed to exit after LAUNCHD_CLEAN_KILL_TIMER seconds. */
-                       embedded_special_privileges     :1, /* The job runs as a non-root user on embedded but has select privileges of the root user. */
-                       did_exec                                        :1, /* The job exec(2)ed successfully. */
-                       holds_ref                                       :1, /* The (anonymous) job called vprocmgr_switch_to_session(). */
-                       jetsam_properties                       :1; /* The job has Jetsam limits in place. */
+       bool    
+       debug                                           :1,     /* man launchd.plist --> Debug */
+       ondemand                                        :1,     /* man launchd.plist --> KeepAlive == false */
+       session_create                          :1,     /* man launchd.plist --> SessionCreate */
+       low_pri_io                                      :1,     /* man launchd.plist --> LowPriorityIO */
+       no_init_groups                          :1,     /* man launchd.plist --> InitGroups */
+       priv_port_has_senders           :1,     /* a legacy mach_init concept to make bootstrap_create_server/service() work */
+       importing_global_env            :1,     /* a hack during job importing */
+       importing_hard_limits           :1,     /* a hack during job importing */
+       setmask                                         :1,     /* man launchd.plist --> Umask */
+       anonymous                                       :1,     /* a process that launchd knows about, but isn't managed by launchd */
+       checkedin                                       :1,     /* a legacy mach_init concept to detect sick jobs */
+       legacy_mach_job                         :1,     /* a job created via bootstrap_create_server() */
+       legacy_LS_job                           :1,     /* a job created via spawn_via_launchd() */
+       inetcompat                                      :1,     /* a legacy job that wants inetd compatible semantics */
+       inetcompat_wait                         :1,     /* a twist on inetd compatibility */
+       start_pending                           :1,     /* an event fired and the job should start, but not necessarily right away */
+       globargv                                        :1,     /* man launchd.plist --> EnableGlobbing */
+       wait4debugger                           :1,     /* man launchd.plist --> WaitForDebugger */
+       wait4debugger_oneshot           :1, /* One-shot WaitForDebugger. */
+       internal_exc_handler            :1,     /* MachExceptionHandler == true */
+       stall_before_exec                       :1,     /* a hack to support an option of spawn_via_launchd() */
+       only_once                                       :1,     /* man launchd.plist --> LaunchOnlyOnce. Note: 5465184 Rename this to "HopefullyNeverExits" */
+       currently_ignored                       :1,     /* Make job_ignore() / job_watch() work. If these calls were balanced, then this wouldn't be necessarily. */
+       forced_peers_to_demand_mode     :1,     /* A job that forced all other jobs to be temporarily launch-on-demand */
+       setnice                                         :1,     /* man launchd.plist --> Nice */
+       removal_pending                         :1,     /* a job was asked to be unloaded/removed while running, we'll remove it after it exits */
+       sent_sigkill                            :1,     /* job_kill() was called */
+       debug_before_kill                       :1,     /* enter the kernel debugger before killing a job */
+       weird_bootstrap                         :1,     /* a hack that launchd+launchctl use during jobmgr_t creation */
+       start_on_mount                          :1,     /* man launchd.plist --> StartOnMount */
+       per_user                                        :1,     /* This job is a per-user launchd managed by the PID 1 launchd */
+       unload_at_mig_return            :1,     /* A job thoroughly confused launchd. We need to unload it ASAP */
+       abandon_pg                                      :1,     /* man launchd.plist --> AbandonProcessGroup */
+       ignore_pg_at_shutdown           :1, /* During shutdown, do not send SIGTERM to stray processes in the process group of this job. */
+       poll_for_vfs_changes            :1,     /* a hack to work around the fact that kqueues don't work on all filesystems */
+       deny_job_creation                       :1,     /* Don't let this job create new 'job_t' objects in launchd */
+       kill_via_shmem                          :1,     /* man launchd.plist --> EnableTransactions */
+       sent_kill_via_shmem                     :1,     /* We need to 'kill_via_shmem' once-and-only-once */
+       clean_kill                                      :1, /* The job was sent SIGKILL because it was clean. */
+       kill_after_sample                       :1, /* The job is to be killed after sampling. */
+       reap_after_trace                        :1,     /* The job exited before sample did, so we should reap it after sample is done. */
+       nosy                                            :1, /* The job has an OtherJobEnabled KeepAlive criterion. */
+       crashed                                         :1, /* The job is the default Mach exception handler, and it crashed. */
+       reaped                                          :1, /* We've received NOTE_EXIT for the job. */
+       stopped                                         :1, /* job_stop() was called. */
+       jetsam_frontmost                        :1, /* The job is considered "frontmost" by Jetsam. */
+       needs_kickoff                           :1, /* The job is to be kept alive continuously, but it must be initially kicked off. */
+       is_bootstrapper                         :1, /* The job is a bootstrapper. */
+       has_console                                     :1, /* The job owns the console. */
+       embedded_special_privileges     :1, /* The job runs as a non-root user on embedded but has select privileges of the root user. */
+       did_exec                                        :1, /* The job exec(2)ed successfully. */
+       xpcproxy_did_exec                       :1, /* The job is an XPC service, and XPC proxy successfully exec(3)ed. */
+       holds_ref                                       :1, /* The (anonymous) job called vprocmgr_switch_to_session(). */
+       jetsam_properties                       :1, /* The job has Jetsam limits in place. */
+       dedicated_instance                      :1, /* This job was created as the result of a look up of a service provided by a per-lookup job. */
+       multiple_instances                      :1, /* The job supports creating additional instances of itself. */
+       former_subjob                           :1, /* The sub-job was already removed from the parent's list of sub-jobs. */
+       event_monitor                           :1, /* The job is responsible for monitoring external events for this launchd. */
+       removing                                        :1, /* A lame hack. */
+       disable_aslr                            :1, /* Disable ASLR when launching this job. */
+       xpc_service                                     :1, /* The job is an XPC Service. */
+       shutdown_monitor                        :1, /* The job is the Performance team's shutdown monitor. */
+       dirty_at_shutdown                       :1, /* We should open a transaction for the job when shutdown begins. */
+       workaround9359725                       :1; /* The job was sent SIGKILL but did not exit in a timely fashion, indicating a kernel bug. */
+
        mode_t mask;
        pid_t tracing_pid;
        mode_t mask;
        pid_t tracing_pid;
-       mach_port_t audit_session;
+       mach_port_t asport;
+       /* Only set for per-user launchd's. */
+       au_asid_t asid;
        uuid_t expected_audit_uuid;
        const char label[0];
 };
 
        uuid_t expected_audit_uuid;
        const char label[0];
 };
 
-#define LABEL_HASH_SIZE 53
-
-static LIST_HEAD(, job_s) label_hash[LABEL_HASH_SIZE];
 static size_t hash_label(const char *label) __attribute__((pure));
 static size_t hash_ms(const char *msstr) __attribute__((pure));
 static SLIST_HEAD(, job_s) s_curious_jobs;
 static size_t hash_label(const char *label) __attribute__((pure));
 static size_t hash_ms(const char *msstr) __attribute__((pure));
 static SLIST_HEAD(, job_s) s_curious_jobs;
@@ -586,6 +679,7 @@ static void job_start(job_t j);
 static void job_start_child(job_t j) __attribute__((noreturn));
 static void job_setup_attributes(job_t j);
 static bool job_setup_machport(job_t j);
 static void job_start_child(job_t j) __attribute__((noreturn));
 static void job_setup_attributes(job_t j);
 static bool job_setup_machport(job_t j);
+static kern_return_t job_setup_exit_port(job_t j);
 static void job_setup_fd(job_t j, int target_fd, const char *path, int flags);
 static void job_postfork_become_user(job_t j);
 static void job_postfork_test_user(job_t j);
 static void job_setup_fd(job_t j, int target_fd, const char *path, int flags);
 static void job_postfork_become_user(job_t j);
 static void job_postfork_test_user(job_t j);
@@ -599,7 +693,11 @@ static void job_log_stray_pg(job_t j);
 static void job_log_children_without_exec(job_t j);
 static job_t job_new_anonymous(jobmgr_t jm, pid_t anonpid) __attribute__((malloc, nonnull, warn_unused_result));
 static job_t job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv) __attribute__((malloc, nonnull(1,2), warn_unused_result));
 static void job_log_children_without_exec(job_t j);
 static job_t job_new_anonymous(jobmgr_t jm, pid_t anonpid) __attribute__((malloc, nonnull, warn_unused_result));
 static job_t job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv) __attribute__((malloc, nonnull(1,2), warn_unused_result));
+#ifndef __LAUNCH_DISABLE_XPC_SUPPORT__
+static job_t job_new_alias(jobmgr_t jm, job_t src);
+#endif
 static job_t job_new_via_mach_init(job_t j, const char *cmd, uid_t uid, bool ond) __attribute__((malloc, nonnull, warn_unused_result));
 static job_t job_new_via_mach_init(job_t j, const char *cmd, uid_t uid, bool ond) __attribute__((malloc, nonnull, warn_unused_result));
+static job_t job_new_subjob(job_t j, uuid_t identifier);
 static void job_kill(job_t j);
 static void job_uncork_fork(job_t j);
 static void job_log_stdouterr(job_t j);
 static void job_kill(job_t j);
 static void job_uncork_fork(job_t j);
 static void job_log_stdouterr(job_t j);
@@ -608,7 +706,9 @@ static void job_log_error(job_t j, int pri, const char *msg, ...) __attribute__(
 static void job_log_bug(job_t j, unsigned int line);
 static void job_log_stdouterr2(job_t j, const char *msg, ...);
 static void job_set_exception_port(job_t j, mach_port_t port);
 static void job_log_bug(job_t j, unsigned int line);
 static void job_log_stdouterr2(job_t j, const char *msg, ...);
 static void job_set_exception_port(job_t j, mach_port_t port);
-static kern_return_t job_handle_mpm_wait(job_t j, mach_port_t srp, int *waitstatus);
+static kern_return_t job_mig_spawn_internal(job_t j, vm_offset_t indata, mach_msg_type_number_t indataCnt, mach_port_t asport, job_t *outj);
+static void job_open_shutdown_transaction(job_t ji);
+static void job_close_shutdown_transaction(job_t ji);
 
 static const struct {
        const char *key;
 
 static const struct {
        const char *key;
@@ -632,15 +732,20 @@ static bool cronemu_mday(struct tm *wtm, int mday, int hour, int min);
 static bool cronemu_hour(struct tm *wtm, int hour, int min);
 static bool cronemu_min(struct tm *wtm, int min);
 
 static bool cronemu_hour(struct tm *wtm, int hour, int min);
 static bool cronemu_min(struct tm *wtm, int min);
 
+/* These functions are a total nightmare to get to through headers.
+ * See rdar://problem/8223092.
+ */
+typedef __darwin_mach_port_t fileport_t;
+#define FILEPORT_NULL ((fileport_t)0)
+extern int fileport_makeport(int, fileport_t *);
+extern int fileport_makefd(fileport_t);
+
 /* miscellaneous file local functions */
 static size_t get_kern_max_proc(void);
 static int dir_has_files(job_t j, const char *path);
 static char **mach_cmd2argv(const char *string);
 static size_t our_strhash(const char *s) __attribute__((pure));
 static void extract_rcsid_substr(const char *i, char *o, size_t osz);
 /* miscellaneous file local functions */
 static size_t get_kern_max_proc(void);
 static int dir_has_files(job_t j, const char *path);
 static char **mach_cmd2argv(const char *string);
 static size_t our_strhash(const char *s) __attribute__((pure));
 static void extract_rcsid_substr(const char *i, char *o, size_t osz);
-static void simulate_pid1_crash(void);
-static pid_t basic_spawn(job_t j, void (*what_to_do)(job_t));
-static void take_sample(job_t j);
 
 void eliminate_double_reboot(void);
 
 
 void eliminate_double_reboot(void);
 
@@ -650,7 +755,12 @@ static size_t total_anon_children;
 static mach_port_t the_exception_server;
 static job_t workaround_5477111;
 static LIST_HEAD(, job_s) s_needing_sessions;
 static mach_port_t the_exception_server;
 static job_t workaround_5477111;
 static LIST_HEAD(, job_s) s_needing_sessions;
+static LIST_HEAD(, eventsystem) _s_event_systems;
+static job_t _s_event_monitor;
+static job_t _s_shutdown_monitor;
+static mach_port_t _s_event_update_port;
 mach_port_t g_audit_session_port = MACH_PORT_NULL;
 mach_port_t g_audit_session_port = MACH_PORT_NULL;
+static uint32_t s_jetsam_sequence_id;
 
 #if !TARGET_OS_EMBEDDED
 static job_t s_embedded_privileged_job = (job_t)&root_jobmgr;
 
 #if !TARGET_OS_EMBEDDED
 static job_t s_embedded_privileged_job = (job_t)&root_jobmgr;
@@ -687,7 +797,7 @@ job_ignore(job_t j)
 
        if (j->poll_for_vfs_changes) {
                j->poll_for_vfs_changes = false;
 
        if (j->poll_for_vfs_changes) {
                j->poll_for_vfs_changes = false;
-               job_assumes(j, kevent_mod((uintptr_t)&j->semaphores, EVFILT_TIMER, EV_DELETE, 0, 0, j) != -1);
+               (void)job_assumes(j, kevent_mod((uintptr_t)&j->semaphores, EVFILT_TIMER, EV_DELETE, 0, 0, j) != -1);
        }
 
        SLIST_FOREACH(sg, &j->sockets, sle) {
        }
 
        SLIST_FOREACH(sg, &j->sockets, sle) {
@@ -737,73 +847,53 @@ job_stop(job_t j)
        char extralog[100];
        int32_t newval = 1;
 
        char extralog[100];
        int32_t newval = 1;
 
-       if (unlikely(!j->p || j->anonymous)) {
+       if (unlikely(!j->p || j->stopped || j->anonymous)) {
                return;
        }
                return;
        }
-       
-#if !TARGET_OS_EMBEDDED
-       if (j->kill_via_shmem && !g_force_old_kill_path) {
-               if (j->shmem) {
-                       if (!j->sent_kill_via_shmem) {
-                               j->shmem->vp_shmem_flags |= VPROC_SHMEM_EXITING;
-                               newval = __sync_sub_and_fetch(&j->shmem->vp_shmem_transaction_cnt, 1);
-                               j->sent_kill_via_shmem = true;
-                       } else {
-                               newval = j->shmem->vp_shmem_transaction_cnt;
-                       }
-               } else {
-                       newval = -1;
-               }
-       } else if( j->kill_via_shmem ) {
-               job_log(j, LOG_DEBUG, "Stopping transactional job the old-fashioned way.");
-       }
-#endif
 
 #if TARGET_OS_EMBEDDED
 
 #if TARGET_OS_EMBEDDED
-       if( g_embedded_privileged_action && s_embedded_privileged_job ) {
-               if( !job_assumes(j, s_embedded_privileged_job->username != NULL && j->username != NULL) ) {
+       if (g_embedded_privileged_action && s_embedded_privileged_job) {
+               if (!job_assumes(j, s_embedded_privileged_job->username != NULL && j->username != NULL)) {
                        errno = EPERM;
                        return;
                }
        
                        errno = EPERM;
                        return;
                }
        
-               if( strcmp(j->username, s_embedded_privileged_job->username) != 0 ) {
+               if (strcmp(j->username, s_embedded_privileged_job->username) != 0) {
                        errno = EPERM;
                        return;
                }
                        errno = EPERM;
                        return;
                }
-       } else if( g_embedded_privileged_action ) {
+       } else if (g_embedded_privileged_action) {
                errno = EINVAL;
                return;
        }
 #endif
 
                errno = EINVAL;
                return;
        }
 #endif
 
+       if (j->kill_via_shmem) {
+               if (j->shmem) {
+                       if (!j->sent_kill_via_shmem) {
+                               j->shmem->vp_shmem_flags |= VPROC_SHMEM_EXITING;
+                               newval = __sync_sub_and_fetch(&j->shmem->vp_shmem_transaction_cnt, 1);
+                               j->sent_kill_via_shmem = true;
+                       } else {
+                               newval = j->shmem->vp_shmem_transaction_cnt;
+                       }
+               } else {
+                       newval = -1;
+               }
+       }
+
        j->sent_signal_time = runtime_get_opaque_time();
 
        if (newval < 0) {
                j->clean_kill = true;
                job_kill(j);
        } else {
        j->sent_signal_time = runtime_get_opaque_time();
 
        if (newval < 0) {
                j->clean_kill = true;
                job_kill(j);
        } else {
-               /*
-                * If sampling is enabled and SAMPLE_TIMEOUT is earlier than the job exit_timeout,
-                * then set a timer for SAMPLE_TIMEOUT seconds after killing
-                */
-               unsigned int exit_timeout = j->exit_timeout;
-               bool do_sample = do_apple_internal_logging;
-               unsigned int timeout = exit_timeout;
+               (void)job_assumes(j, runtime_kill(j->p, SIGTERM) != -1);
 
 
-               if (do_sample && (!exit_timeout || (LAUNCHD_SAMPLE_TIMEOUT < exit_timeout))) {
-                       timeout = LAUNCHD_SAMPLE_TIMEOUT;
-               }
-
-               job_assumes(j, runtime_kill(j->p, SIGTERM) != -1);
-
-               if (timeout) {
-                       j->sampling_complete = !do_sample;
-                       job_assumes(j, kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER,
-                                               EV_ADD|EV_ONESHOT, NOTE_SECONDS, timeout, j) != -1);
-               }
-
-               if (!exit_timeout) {
-                       job_log(j, LOG_DEBUG, "This job has an infinite exit timeout");
+               if (j->exit_timeout) {
+                       (void)job_assumes(j, kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, j->exit_timeout, j) != -1);
+               } else {
+                       job_log(j, LOG_NOTICE, "This job has an infinite exit timeout");
                }
 
                if (j->kill_via_shmem) {
                }
 
                if (j->kill_via_shmem) {
@@ -961,8 +1051,10 @@ jobmgr_log_active_jobs(jobmgr_t jm)
        }
 
        LIST_FOREACH(ji, &jm->jobs, sle) {
        }
 
        LIST_FOREACH(ji, &jm->jobs, sle) {
-               if( (why_active = job_active(ji)) ) {
-                       job_log(ji, LOG_DEBUG | LOG_CONSOLE, "%s", why_active);
+               if ((why_active = job_active(ji))) {
+                       if (ji->p != 1) {
+                               job_log(ji, LOG_DEBUG | LOG_CONSOLE, "%s", why_active);
+                       }
                }
        }
 }
                }
        }
 }
@@ -970,7 +1062,7 @@ jobmgr_log_active_jobs(jobmgr_t jm)
 static void
 jobmgr_still_alive_with_check(jobmgr_t jm)
 {
 static void
 jobmgr_still_alive_with_check(jobmgr_t jm)
 {
-       jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Still alive with %lu/%lu (normal/anonymous) children. In %s phase of shutdown.", total_children, total_anon_children, s_phases[jm->shutdown_phase]);
+       jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Still alive with %lu/%lu (normal/anonymous) children.", total_children, total_anon_children);
        jobmgr_log_active_jobs(jm);
 }
 
        jobmgr_log_active_jobs(jm);
 }
 
@@ -980,6 +1072,22 @@ jobmgr_shutdown(jobmgr_t jm)
        jobmgr_t jmi, jmn;
        jobmgr_log(jm, LOG_DEBUG, "Beginning job manager shutdown with flags: %s", reboot_flags_to_C_names(jm->reboot_flags));
 
        jobmgr_t jmi, jmn;
        jobmgr_log(jm, LOG_DEBUG, "Beginning job manager shutdown with flags: %s", reboot_flags_to_C_names(jm->reboot_flags));
 
+       jm->shutdown_time = runtime_get_wall_time() / USEC_PER_SEC;
+
+       struct tm curtime;
+       (void)localtime_r(&jm->shutdown_time, &curtime);
+
+       char date[26];
+       (void)asctime_r(&curtime, date);
+       /* Trim the new line that asctime_r(3) puts there for some reason. */
+       date[24] = 0;
+
+       if (jm == root_jobmgr && pid1_magic) {
+               jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Userspace shutdown begun at: %s", date);
+       } else {
+               jobmgr_log(jm, LOG_DEBUG, "Job manager shutdown begun at: %s", date);
+       }
+
        jm->shutting_down = true;
 
        SLIST_FOREACH_SAFE(jmi, &jm->submgrs, sle, jmn) {
        jm->shutting_down = true;
 
        SLIST_FOREACH_SAFE(jmi, &jm->submgrs, sle, jmn) {
@@ -987,11 +1095,13 @@ jobmgr_shutdown(jobmgr_t jm)
        }
        
        if (jm->parentmgr == NULL && pid1_magic) {
        }
        
        if (jm->parentmgr == NULL && pid1_magic) {
-               jobmgr_assumes(jm, kevent_mod((uintptr_t)jm, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, 5, jm));
-       #if !TARGET_OS_EMBEDDED
-               /* Kill the update thread. */
-               jobmgr_assumes(jm, __sync_sub_and_fetch(&g_sync_frequency, 30) == 0);
-       #endif
+               (void)jobmgr_assumes(jm, kevent_mod((uintptr_t)jm, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, 5, jm));
+
+               /* Spawn the shutdown monitor. */
+               if (_s_shutdown_monitor && !_s_shutdown_monitor->p) {
+                       job_log(_s_shutdown_monitor, LOG_NOTICE | LOG_CONSOLE, "Starting shutdown monitor.");
+                       job_dispatch(_s_shutdown_monitor, true);
+               }
        }
 
        return jobmgr_do_garbage_collection(jm);
        }
 
        return jobmgr_do_garbage_collection(jm);
@@ -1010,20 +1120,60 @@ jobmgr_remove(jobmgr_t jm)
                }
        }
 
                }
        }
 
-       while( (ji = LIST_FIRST(&jm->jobs)) ) {
-               if( !ji->anonymous && ji->p ) {
-                       job_log(ji, LOG_WARNING | LOG_CONSOLE, "Job has overstayed its welcome. Forcing removal.");
+       while ((ji = LIST_FIRST(&jm->jobs))) {
+               if (!ji->anonymous && !job_assumes(ji, ji->p == 0)) {
                        ji->p = 0;
                }
                job_remove(ji);
        }
 
        if (jm->req_port) {
                        ji->p = 0;
                }
                job_remove(ji);
        }
 
        if (jm->req_port) {
-               jobmgr_assumes(jm, launchd_mport_deallocate(jm->req_port) == KERN_SUCCESS);
+               (void)jobmgr_assumes(jm, launchd_mport_deallocate(jm->req_port) == KERN_SUCCESS);
        }
        }
-
        if (jm->jm_port) {
        if (jm->jm_port) {
-               jobmgr_assumes(jm, launchd_mport_close_recv(jm->jm_port) == KERN_SUCCESS);
+               (void)jobmgr_assumes(jm, launchd_mport_close_recv(jm->jm_port) == KERN_SUCCESS);
+       }
+
+       if (jm->req_bsport) {
+               (void)jobmgr_assumes(jm, launchd_mport_deallocate(jm->req_bsport) == KERN_SUCCESS);
+       }
+       if (jm->req_excport) {
+               (void)jobmgr_assumes(jm, launchd_mport_deallocate(jm->req_excport) == KERN_SUCCESS);
+       }
+       if (jm->req_asport) {
+               (void)jobmgr_assumes(jm, launchd_mport_deallocate(jm->req_asport) == KERN_SUCCESS);
+       }
+#if !TARGET_OS_EMBEDDED
+       if (jm->req_rport) {
+               kern_return_t kr = xpc_call_wakeup(jm->req_rport, jm->error);
+               if (!(kr == KERN_SUCCESS || kr == MACH_SEND_INVALID_DEST)) {
+                       /* If the originator went away, the reply port will be a dead name,
+                        * and we expect this to fail.
+                        */
+                       errno = kr;
+                       (void)jobmgr_assumes(jm, kr == KERN_SUCCESS);
+               }
+       }
+#endif
+       if (jm->req_ctx) {
+               (void)jobmgr_assumes(jm, vm_deallocate(mach_task_self(), jm->req_ctx, jm->req_ctx_sz) == KERN_SUCCESS);
+       }
+
+       time_t ts = runtime_get_wall_time() / USEC_PER_SEC;
+       struct tm curtime;
+       (void)localtime_r(&ts, &curtime);
+
+       char date[26];
+       (void)asctime_r(&curtime, date);
+       date[24] = 0;
+
+       time_t delta = ts - jm->shutdown_time;
+       if (jm == root_jobmgr && pid1_magic) {
+               jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Userspace shutdown finished at: %s", date);
+               jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Userspace shutdown took approximately %ld second%s.", delta, (delta != 1) ? "s" : "");
+       } else {
+               jobmgr_log(jm, LOG_DEBUG, "Job manager shutdown finished at: %s", date);
+               jobmgr_log(jm, LOG_DEBUG, "Job manager shutdown took approximately %ld second%s.", delta, (delta != 1) ? "s" : "");
        }
 
        if (jm->parentmgr) {
        }
 
        if (jm->parentmgr) {
@@ -1032,9 +1182,10 @@ jobmgr_remove(jobmgr_t jm)
        } else if (pid1_magic) {
                eliminate_double_reboot();
                launchd_log_vm_stats();
        } else if (pid1_magic) {
                eliminate_double_reboot();
                launchd_log_vm_stats();
+               jobmgr_log_stray_children(jm, true);
                jobmgr_log(root_jobmgr, LOG_NOTICE | LOG_CONSOLE, "About to call: reboot(%s).", reboot_flags_to_C_names(jm->reboot_flags));
                runtime_closelog();
                jobmgr_log(root_jobmgr, LOG_NOTICE | LOG_CONSOLE, "About to call: reboot(%s).", reboot_flags_to_C_names(jm->reboot_flags));
                runtime_closelog();
-               jobmgr_assumes(jm, reboot(jm->reboot_flags) != -1);
+               (void)jobmgr_assumes(jm, reboot(jm->reboot_flags) != -1);
        } else {
                jobmgr_log(jm, LOG_DEBUG, "About to exit");
                runtime_closelog();
        } else {
                jobmgr_log(jm, LOG_DEBUG, "About to exit");
                runtime_closelog();
@@ -1054,24 +1205,49 @@ job_remove(job_t j)
        struct machservice *ms;
        struct limititem *li;
        struct envitem *ei;
        struct machservice *ms;
        struct limititem *li;
        struct envitem *ei;
-       
+
+       if (j->alias) {
+               /* HACK: Egregious code duplication. But as with machservice_delete(),
+                * job aliases can't (and shouldn't) have any complex behaviors 
+                * associated with them.
+                */
+               while ((ms = SLIST_FIRST(&j->machservices))) {
+                       machservice_delete(j, ms, false);
+               }
+
+               LIST_REMOVE(j, sle);
+               LIST_REMOVE(j, label_hash_sle);
+               free(j);
+               return;
+       }
+
 #if TARGET_OS_EMBEDDED
 #if TARGET_OS_EMBEDDED
-       if( g_embedded_privileged_action && s_embedded_privileged_job ) {
-               if( !job_assumes(j, s_embedded_privileged_job->username != NULL && j->username != NULL) ) {
+       if (g_embedded_privileged_action && s_embedded_privileged_job) {
+               if (!job_assumes(j, s_embedded_privileged_job->username != NULL && j->username != NULL)) {
                        errno = EPERM;
                        return;
                }
        
                        errno = EPERM;
                        return;
                }
        
-               if( strcmp(j->username, s_embedded_privileged_job->username) != 0 ) {
+               if (strcmp(j->username, s_embedded_privileged_job->username) != 0) {
                        errno = EPERM;
                        return;
                }
                        errno = EPERM;
                        return;
                }
-       } else if( g_embedded_privileged_action ) {
+       } else if (g_embedded_privileged_action) {
                errno = EINVAL;
                return;
        }
 #endif
        
                errno = EINVAL;
                return;
        }
 #endif
        
+       /* Do this BEFORE we check and see whether the job is still active. If we're a
+        * sub-job, we're being removed due to the parent job removing us. Therefore, the
+        * parent job will free itself after this call completes. So if we defer removing
+        * ourselves from the parent's list, we'll crash when we finally get around to it.
+        */
+       if (j->dedicated_instance && !j->former_subjob) {
+               LIST_REMOVE(j, subjob_sle);
+               j->former_subjob = true;
+       }
+       
        if (unlikely(j->p)) {
                if (j->anonymous) {
                        job_reap(j);
        if (unlikely(j->p)) {
                if (j->anonymous) {
                        job_reap(j);
@@ -1082,11 +1258,15 @@ job_remove(job_t j)
                                j->removal_pending = true;
                                job_stop(j);
                        }
                                j->removal_pending = true;
                                job_stop(j);
                        }
+                       
                        return;
                }
        }
        
                        return;
                }
        }
        
-       job_dispatch_curious_jobs(j);
+       if (!j->removing) {
+               j->removing = true;
+               job_dispatch_curious_jobs(j);
+       }
 
        ipc_close_all_with_job(j);
 
 
        ipc_close_all_with_job(j);
 
@@ -1104,23 +1284,19 @@ job_remove(job_t j)
        }
 
        if (!job_assumes(j, j->fork_fd == 0)) {
        }
 
        if (!job_assumes(j, j->fork_fd == 0)) {
-               job_assumes(j, runtime_close(j->fork_fd) != -1);
+               (void)job_assumes(j, runtime_close(j->fork_fd) != -1);
        }
 
        if (j->stdin_fd) {
        }
 
        if (j->stdin_fd) {
-               job_assumes(j, runtime_close(j->stdin_fd) != -1);
+               (void)job_assumes(j, runtime_close(j->stdin_fd) != -1);
        }
 
        if (!job_assumes(j, j->log_redirect_fd == 0)) {
        }
 
        if (!job_assumes(j, j->log_redirect_fd == 0)) {
-               job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
+               (void)job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
        }
 
        if (j->j_port) {
        }
 
        if (j->j_port) {
-               job_assumes(j, launchd_mport_close_recv(j->j_port) == KERN_SUCCESS);
-       }
-
-       if (!job_assumes(j, j->wait_reply_port == MACH_PORT_NULL)) {
-               job_assumes(j, launchd_mport_deallocate(j->wait_reply_port) == KERN_SUCCESS);
+               (void)job_assumes(j, launchd_mport_close_recv(j->j_port) == KERN_SUCCESS);
        }
 
        while ((sg = SLIST_FIRST(&j->sockets))) {
        }
 
        while ((sg = SLIST_FIRST(&j->sockets))) {
@@ -1147,6 +1323,37 @@ job_remove(job_t j)
        while ((w4r = SLIST_FIRST(&j->removal_watchers))) {
                waiting4removal_delete(j, w4r);
        }
        while ((w4r = SLIST_FIRST(&j->removal_watchers))) {
                waiting4removal_delete(j, w4r);
        }
+       
+       struct externalevent *eei = NULL;
+       while ((eei = LIST_FIRST(&j->events))) {
+               eventsystem_ping();
+               externalevent_delete(eei);
+       }
+
+#if 0
+       /* Event systems exist independently of an actual monitor job. They're
+        * created on-demand when a job has a LaunchEvents dictionary. So we
+        * really don't need to get rid of them.
+        */
+       if (j->event_monitor) {
+               struct eventsystem *esi = NULL;
+               while ((esi = LIST_FIRST(&_s_event_systems))) {
+                       eventsystem_delete(esi);
+               }
+       }
+#else
+       if (false) {
+               /* Make gcc happy. */
+               eventsystem_delete(NULL);
+       }
+       if (j->event_monitor) {
+               if (_s_event_update_port != MACH_PORT_NULL) {
+                       (void)job_assumes(j, launchd_mport_deallocate(_s_event_update_port) == KERN_SUCCESS);
+                       _s_event_update_port = MACH_PORT_NULL;
+               }
+               _s_event_monitor = NULL;
+       }
+#endif
 
        if (j->prog) {
                free(j->prog);
 
        if (j->prog) {
                free(j->prog);
@@ -1193,34 +1400,50 @@ job_remove(job_t j)
        }
        if (j->start_interval) {
                runtime_del_weak_ref();
        }
        if (j->start_interval) {
                runtime_del_weak_ref();
-               job_assumes(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_DELETE, 0, 0, NULL) != -1);
+               (void)job_assumes(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_DELETE, 0, 0, NULL) != -1);
        }
        if (j->poll_for_vfs_changes) {
        }
        if (j->poll_for_vfs_changes) {
-               job_assumes(j, kevent_mod((uintptr_t)&j->semaphores, EVFILT_TIMER, EV_DELETE, 0, 0, j) != -1);
+               (void)job_assumes(j, kevent_mod((uintptr_t)&j->semaphores, EVFILT_TIMER, EV_DELETE, 0, 0, j) != -1);
        }
        }
-       if( j->exit_timeout ) {
+       if (j->exit_timeout) {
                /* Not a big deal if this fails. It means that the timer's already been freed. */
                kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
        }
                /* Not a big deal if this fails. It means that the timer's already been freed. */
                kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
        }
-       if( j->jetsam_properties ) {
+       if (j->jetsam_properties) {
                LIST_REMOVE(j, jetsam_sle);
                j->mgr->jetsam_jobs_cnt--;
        }
                LIST_REMOVE(j, jetsam_sle);
                j->mgr->jetsam_jobs_cnt--;
        }
-       if( j->audit_session != MACH_PORT_NULL ) {
-               job_assumes(j, mach_port_deallocate(mach_task_self(), j->audit_session) == KERN_SUCCESS);
+       if (j->asport != MACH_PORT_NULL) {
+               (void)job_assumes(j, launchd_mport_deallocate(j->asport) == KERN_SUCCESS);
        }
        }
-       if( !uuid_is_null(j->expected_audit_uuid) ) {
+       if (!uuid_is_null(j->expected_audit_uuid)) {
                LIST_REMOVE(j, needing_session_sle);
        }
                LIST_REMOVE(j, needing_session_sle);
        }
-       if( j->embedded_special_privileges ) {
+       if (j->embedded_special_privileges) {
                s_embedded_privileged_job = NULL;
        }
                s_embedded_privileged_job = NULL;
        }
+       if (j->shutdown_monitor) {
+               _s_shutdown_monitor = NULL;
+       }
+       if (j->workaround9359725) {
+               /* We may have forcibly removed this job by simulating an exit. If this
+                * is the case, we don't want to hear about these events anymore, lest
+                * we get a stale context pointer and crash trying to dereference it.
+                */
+               kevent_mod((uintptr_t)j->p, EVFILT_PROC, EV_DELETE, 0, 0, NULL);
+       }
        
        kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
        
        LIST_REMOVE(j, sle);
        LIST_REMOVE(j, label_hash_sle);
 
        
        kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
        
        LIST_REMOVE(j, sle);
        LIST_REMOVE(j, label_hash_sle);
 
+       job_t ji = NULL;
+       job_t jit = NULL;
+       LIST_FOREACH_SAFE(ji, &j->subjobs, subjob_sle, jit) {
+               job_remove(ji);
+       }
+       
        job_log(j, LOG_DEBUG, "Removed");
 
        free(j);
        job_log(j, LOG_DEBUG, "Removed");
 
        free(j);
@@ -1297,17 +1520,40 @@ job_setup_machport(job_t j)
        }
 
        if (!job_assumes(j, launchd_mport_notify_req(j->j_port, MACH_NOTIFY_NO_SENDERS) == KERN_SUCCESS)) {
        }
 
        if (!job_assumes(j, launchd_mport_notify_req(j->j_port, MACH_NOTIFY_NO_SENDERS) == KERN_SUCCESS)) {
-               job_assumes(j, launchd_mport_close_recv(j->j_port) == KERN_SUCCESS);
+               (void)job_assumes(j, launchd_mport_close_recv(j->j_port) == KERN_SUCCESS);
                goto out_bad;
        }
 
        return true;
 out_bad2:
                goto out_bad;
        }
 
        return true;
 out_bad2:
-       job_assumes(j, launchd_mport_close_recv(j->j_port) == KERN_SUCCESS);
+       (void)job_assumes(j, launchd_mport_close_recv(j->j_port) == KERN_SUCCESS);
 out_bad:
        return false;
 }
 
 out_bad:
        return false;
 }
 
+kern_return_t
+job_setup_exit_port(job_t j)
+{
+       kern_return_t kr = launchd_mport_create_recv(&j->exit_status_port);
+       if (!job_assumes(j, kr == KERN_SUCCESS)) {
+               return MACH_PORT_NULL;
+       }
+
+       struct mach_port_limits limits = {
+               .mpl_qlimit = 1,
+       };
+       kr = mach_port_set_attributes(mach_task_self(), j->exit_status_port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, sizeof(limits));
+       (void)job_assumes(j, kr == KERN_SUCCESS);
+
+       kr = launchd_mport_make_send_once(j->exit_status_port, &j->exit_status_dest);
+       if (!job_assumes(j, kr == KERN_SUCCESS)) {
+               (void)job_assumes(j, launchd_mport_close_recv(j->exit_status_port) == KERN_SUCCESS);
+               j->exit_status_port = MACH_PORT_NULL;
+       }
+
+       return kr;
+}
+
 job_t 
 job_new_via_mach_init(job_t j, const char *cmd, uid_t uid, bool ond)
 {
 job_t 
 job_new_via_mach_init(job_t j, const char *cmd, uid_t uid, bool ond)
 {
@@ -1348,25 +1594,10 @@ out_bad:
        return NULL;
 }
 
        return NULL;
 }
 
-kern_return_t
-job_handle_mpm_wait(job_t j, mach_port_t srp, int *waitstatus)
-{
-       if (j->p) {
-               j->wait_reply_port = srp;
-               return MIG_NO_REPLY;
-       }
-
-       *waitstatus = j->last_exit_status;
-
-       return 0;
-}
-
 job_t
 job_new_anonymous(jobmgr_t jm, pid_t anonpid)
 {
 job_t
 job_new_anonymous(jobmgr_t jm, pid_t anonpid)
 {
-       int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, anonpid };
-       struct kinfo_proc kp;
-       size_t len = sizeof(kp);
+       struct proc_bsdshortinfo proc;
        bool shutdown_state;
        job_t jp = NULL, jr = NULL;
        uid_t kp_euid, kp_uid, kp_svuid;
        bool shutdown_state;
        job_t jp = NULL, jr = NULL;
        uid_t kp_euid, kp_uid, kp_svuid;
@@ -1383,62 +1614,59 @@ job_new_anonymous(jobmgr_t jm, pid_t anonpid)
                return NULL;
        }
 
                return NULL;
        }
 
-       if (!jobmgr_assumes(jm, sysctl(mib, 4, &kp, &len, NULL, 0) != -1)) {
-               return NULL;
-       }
-
-       if (unlikely(len != sizeof(kp))) {
-               jobmgr_log(jm, LOG_DEBUG, "Tried to create an anonymous job for nonexistent PID: %u", anonpid);
-               errno = ESRCH;
+       /* libproc returns the number of bytes written into the buffer upon success,
+        * zero on failure.
+        */
+       if (proc_pidinfo(anonpid, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
+               if (errno != ESRCH) {
+                       (void)jobmgr_assumes(jm, errno == 0);
+               }
                return NULL;
        }
 
                return NULL;
        }
 
-       if (!jobmgr_assumes(jm, kp.kp_proc.p_comm[0] != '\0')) {
+       if (!jobmgr_assumes(jm, proc.pbsi_comm[0] != '\0')) {
                errno = EINVAL;
                return NULL;
        }
 
                errno = EINVAL;
                return NULL;
        }
 
-       if (unlikely(kp.kp_proc.p_stat == SZOMB)) {
-               jobmgr_log(jm, LOG_DEBUG, "Tried to create an anonymous job for zombie PID %u: %s", anonpid, kp.kp_proc.p_comm);
+       if (unlikely(proc.pbsi_status == SZOMB)) {
+               jobmgr_log(jm, LOG_DEBUG, "Tried to create an anonymous job for zombie PID %u: %s", anonpid, proc.pbsi_comm);
        }
 
        }
 
-       if (unlikely(kp.kp_proc.p_flag & P_SUGID)) {
-               jobmgr_log(jm, LOG_DEBUG, "Inconsistency: P_SUGID is set on PID %u: %s", anonpid, kp.kp_proc.p_comm);
+       if (unlikely(proc.pbsi_flags & P_SUGID)) {
+               jobmgr_log(jm, LOG_DEBUG, "Inconsistency: P_SUGID is set on PID %u: %s", anonpid, proc.pbsi_comm);
        }
 
        }
 
-       kp_euid = kp.kp_eproc.e_ucred.cr_uid;
-       kp_uid = kp.kp_eproc.e_pcred.p_ruid;
-       kp_svuid = kp.kp_eproc.e_pcred.p_svuid;
-       kp_egid = kp.kp_eproc.e_ucred.cr_gid;
-       kp_gid = kp.kp_eproc.e_pcred.p_rgid;
-       kp_svgid = kp.kp_eproc.e_pcred.p_svgid;
+       kp_euid = proc.pbsi_uid;
+       kp_uid = proc.pbsi_ruid;
+       kp_svuid = proc.pbsi_svuid;
+       kp_egid = proc.pbsi_gid;
+       kp_gid = proc.pbsi_rgid;
+       kp_svgid = proc.pbsi_svgid;
 
        if (unlikely(kp_euid != kp_uid || kp_euid != kp_svuid || kp_uid != kp_svuid || kp_egid != kp_gid || kp_egid != kp_svgid || kp_gid != kp_svgid)) {
                jobmgr_log(jm, LOG_DEBUG, "Inconsistency: Mixed credentials (e/r/s UID %u/%u/%u GID %u/%u/%u) detected on PID %u: %s",
 
        if (unlikely(kp_euid != kp_uid || kp_euid != kp_svuid || kp_uid != kp_svuid || kp_egid != kp_gid || kp_egid != kp_svgid || kp_gid != kp_svgid)) {
                jobmgr_log(jm, LOG_DEBUG, "Inconsistency: Mixed credentials (e/r/s UID %u/%u/%u GID %u/%u/%u) detected on PID %u: %s",
-                               kp_euid, kp_uid, kp_svuid, kp_egid, kp_gid, kp_svgid, anonpid, kp.kp_proc.p_comm);
+                               kp_euid, kp_uid, kp_svuid, kp_egid, kp_gid, kp_svgid, anonpid, proc.pbsi_comm);
        }
 
        /* "Fix" for a problem that shouldn't even exist.
         * See rdar://problem/7264615 for the symptom and rdar://problem/5020256
         * as to why this can happen.
         */
        }
 
        /* "Fix" for a problem that shouldn't even exist.
         * See rdar://problem/7264615 for the symptom and rdar://problem/5020256
         * as to why this can happen.
         */
-       if( !jobmgr_assumes(jm, kp.kp_eproc.e_ppid != anonpid) ) {
-               jobmgr_log(jm, LOG_WARNING, "Process has become its own parent through ptrace(3). It should find a different way to do whatever it's doing. Setting PPID to 0: %s", kp.kp_proc.p_comm);
+       if (!jobmgr_assumes(jm, (pid_t)proc.pbsi_ppid != anonpid)) {
+               jobmgr_log(jm, LOG_WARNING, "Process has become its own parent through ptrace(3). It should find a different way to do whatever it's doing. Setting PPID to 0: %s", proc.pbsi_comm);
                errno = EINVAL;
                return NULL;
        }
 
                errno = EINVAL;
                return NULL;
        }
 
-       if (jp && !jp->anonymous && unlikely(!(kp.kp_proc.p_flag & P_EXEC))) {
-               job_log(jp, LOG_DEBUG, "Called *fork(). Please switch to posix_spawn*(), pthreads or launchd. Child PID %u",
-                               kp.kp_proc.p_pid);
-       }
-
        /* A total hack: Normally, job_new() returns an error during shutdown, but anonymous jobs are special. */
        if (unlikely(shutdown_state = jm->shutting_down)) {
                jm->shutting_down = false;
        }
 
        /* A total hack: Normally, job_new() returns an error during shutdown, but anonymous jobs are special. */
        if (unlikely(shutdown_state = jm->shutting_down)) {
                jm->shutting_down = false;
        }
 
-       if (jobmgr_assumes(jm, (jr = job_new(jm, AUTO_PICK_ANONYMOUS_LABEL, kp.kp_proc.p_comm, NULL)) != NULL)) {
+       /* We only set requestor_pid for XPC domains. */
+       const char *whichlabel = (jm->req_pid == anonpid) ? AUTO_PICK_XPC_LABEL : AUTO_PICK_ANONYMOUS_LABEL;
+       if (jobmgr_assumes(jm, (jr = job_new(jm, whichlabel, proc.pbsi_comm, NULL)) != NULL)) {
                u_int proc_fflags = NOTE_EXEC|NOTE_FORK|NOTE_EXIT;
 
                total_anon_children++;
                u_int proc_fflags = NOTE_EXEC|NOTE_FORK|NOTE_EXIT;
 
                total_anon_children++;
@@ -1454,11 +1682,11 @@ job_new_anonymous(jobmgr_t jm, pid_t anonpid)
                        jr->unload_at_mig_return = true;
                }
 
                        jr->unload_at_mig_return = true;
                }
 
-               if (unlikely(shutdown_state && jm->hopefully_first_cnt == 0)) {
+               if (unlikely(shutdown_state)) {
                        job_log(jr, LOG_SCOLDING, "This process showed up to the party while all the guests were leaving. Odds are that it will have a miserable time.");
                }
 
                        job_log(jr, LOG_SCOLDING, "This process showed up to the party while all the guests were leaving. Odds are that it will have a miserable time.");
                }
 
-               job_log(jr, LOG_DEBUG, "Created PID %u anonymously by PPID %u%s%s", anonpid, kp.kp_eproc.e_ppid, jp ? ": " : "", jp ? jp->label : "");
+               job_log(jr, LOG_DEBUG, "Created PID %u anonymously by PPID %u%s%s", anonpid, proc.pbsi_ppid, jp ? ": " : "", jp ? jp->label : "");
        }
 
        if (unlikely(shutdown_state)) {
        }
 
        if (unlikely(shutdown_state)) {
@@ -1471,7 +1699,7 @@ job_new_anonymous(jobmgr_t jm, pid_t anonpid)
         * tree (thereby making it not a tree anymore), we'll find the tracing parent PID of the
         * parent process, which is the child, when we go looking for it in jobmgr_find_by_pid().
         */
         * tree (thereby making it not a tree anymore), we'll find the tracing parent PID of the
         * parent process, which is the child, when we go looking for it in jobmgr_find_by_pid().
         */
-       switch (kp.kp_eproc.e_ppid) {
+       switch (proc.pbsi_ppid) {
                case 0:
                        /* the kernel */
                        break;
                case 0:
                        /* the kernel */
                        break;
@@ -1482,14 +1710,177 @@ job_new_anonymous(jobmgr_t jm, pid_t anonpid)
                        }
                        /* fall through */
                default:
                        }
                        /* fall through */
                default:
-                       jp = jobmgr_find_by_pid(jm, kp.kp_eproc.e_ppid, true);
-                       jobmgr_assumes(jm, jp != NULL);
+                       jp = jobmgr_find_by_pid(jm, proc.pbsi_ppid, true);
+                       if (jobmgr_assumes(jm, jp != NULL)) {
+                               if (jp && !jp->anonymous && unlikely(!(proc.pbsi_flags & P_EXEC))) {
+                                       job_log(jp, LOG_DEBUG, "Called *fork(). Please switch to posix_spawn*(), pthreads or launchd. Child PID %u", proc.pbsi_pid);
+                               }
+                       }
                        break;
        }
 
        return jr;
 }
 
                        break;
        }
 
        return jr;
 }
 
+job_t 
+job_new_subjob(job_t j, uuid_t identifier)
+{
+       char label[0];
+       uuid_string_t idstr;
+       uuid_unparse(identifier, idstr);
+       size_t label_sz = snprintf(label, 0, "%s.%s", j->label, idstr);
+
+       job_t nj = (struct job_s *)calloc(1, sizeof(struct job_s) + label_sz + 1);
+       if (launchd_assumes(nj != NULL)) {
+               nj->kqjob_callback = job_callback;
+               nj->mgr = j->mgr;
+               nj->min_run_time = j->min_run_time;
+               nj->timeout = j->timeout;
+               nj->exit_timeout = j->exit_timeout;
+               
+               snprintf((char *)nj->label, label_sz + 1, "%s.%s", j->label, idstr);
+               
+               /* Set all our simple Booleans that are applicable. */
+               nj->debug = j->debug;
+               nj->ondemand = j->ondemand;
+               nj->checkedin = true;
+               nj->low_pri_io = j->low_pri_io;
+               nj->setmask = j->setmask;
+               nj->wait4debugger = j->wait4debugger;
+               nj->internal_exc_handler = j->internal_exc_handler;
+               nj->setnice = j->setnice;
+               nj->abandon_pg = j->abandon_pg;
+               nj->ignore_pg_at_shutdown = j->ignore_pg_at_shutdown;
+               nj->deny_job_creation = j->deny_job_creation;
+               nj->kill_via_shmem = j->kill_via_shmem;
+               nj->needs_kickoff = j->needs_kickoff;
+               nj->currently_ignored = true;
+               nj->dedicated_instance = true;
+               nj->xpc_service = j->xpc_service;
+               
+               nj->mask = j->mask;
+               uuid_copy(nj->instance_id, identifier);
+               
+               /* These jobs are purely on-demand Mach jobs. */
+               
+               /* {Hard | Soft}ResourceLimits are not supported. */
+               
+               struct machservice *msi = NULL;
+               SLIST_FOREACH(msi, &j->machservices, sle) {
+                       /* Only copy MachServices that were actually declared in the plist.
+                        * So skip over per-PID ones and ones that were created via
+                        * bootstrap_register().
+                        */
+                       if (msi->upfront) {
+                               mach_port_t mp = MACH_PORT_NULL;
+                               struct machservice *msj = machservice_new(nj, msi->name, &mp, msi->per_pid);
+                               if (job_assumes(nj, msj != NULL)) {
+                                       msj->reset = msi->reset;
+                                       msj->delete_on_destruction = msi->delete_on_destruction;
+                                       msj->drain_one_on_crash = msi->drain_one_on_crash;
+                                       msj->drain_all_on_crash = msi->drain_all_on_crash;
+                               }
+                       }
+               }
+               
+               if (j->prog) {
+                       nj->prog = strdup(j->prog);
+               }
+               if (j->argv) {
+                       size_t sz = malloc_size(j->argv);
+                       nj->argv = (char **)malloc(sz);
+                       if (job_assumes(nj, nj->argv != NULL)) {
+                               /* This is the start of our strings. */
+                               char *p = ((char *)nj->argv) + ((j->argc + 1) * sizeof(char *));
+                               
+                               size_t i = 0;
+                               for (i = 0; i < j->argc; i++) {
+                                       (void)strcpy(p, j->argv[i]);
+                                       nj->argv[i] = p;
+                                       p += (strlen(j->argv[i]) + 1);
+                               }
+                               nj->argv[i] = NULL;
+                       }
+                       
+                       nj->argc = j->argc;
+               }
+               
+               /* We ignore global environment variables. */
+               struct envitem *ei = NULL;
+               SLIST_FOREACH(ei, &j->env, sle) {
+                       (void)job_assumes(nj, envitem_new(nj, ei->key, ei->value, false, false));
+               }
+               uuid_string_t val;
+               uuid_unparse(identifier, val);
+               (void)job_assumes(nj, envitem_new(nj, LAUNCH_ENV_INSTANCEID, val, false, false));
+               
+               if (j->rootdir) {
+                       nj->rootdir = strdup(j->rootdir);
+               }
+               if (j->workingdir) {
+                       nj->workingdir = strdup(j->workingdir);
+               }
+               if (j->username) {
+                       nj->username = strdup(j->username);
+               }
+               if (j->groupname) {
+                       nj->groupname = strdup(j->groupname);
+               }
+               /* FIXME: We shouldn't redirect all the output from these jobs to the same
+                * file. We should uniquify the file names.
+                */
+               if (j->stdinpath) {
+                       nj->stdinpath = strdup(j->stdinpath);
+               }
+               if (j->stdoutpath) {
+                       nj->stdoutpath = strdup(j->stdinpath);
+               }
+               if (j->stderrpath) {
+                       nj->stderrpath = strdup(j->stderrpath);
+               }
+               if (j->alt_exc_handler) {
+                       nj->alt_exc_handler = strdup(j->alt_exc_handler);
+               }
+       #if HAVE_SANDBOX
+               if (j->seatbelt_profile) {
+                       nj->seatbelt_profile = strdup(j->seatbelt_profile);
+               }
+       #endif
+               
+       #if HAVE_QUARANTINE
+               if (j->quarantine_data) {
+                       nj->quarantine_data = strdup(j->quarantine_data);
+               }
+               nj->quarantine_data_sz = j->quarantine_data_sz;
+       #endif
+               if (j->j_binpref) {
+                       size_t sz = malloc_size(j->j_binpref);
+                       nj->j_binpref = (cpu_type_t *)malloc(sz);
+                       if (job_assumes(nj, nj->j_binpref)) {
+                               memcpy(&nj->j_binpref, &j->j_binpref, sz);
+                       }
+               }
+               
+               /* JetsamPriority is unsupported. */
+               
+               if (j->asport != MACH_PORT_NULL) {
+                       (void)job_assumes(nj, launchd_mport_copy_send(j->asport) == KERN_SUCCESS);
+                       nj->asport = j->asport;
+               }
+               
+               LIST_INSERT_HEAD(&nj->mgr->jobs, nj, sle);
+               
+               jobmgr_t where2put = root_jobmgr;
+               if (j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN) {
+                       where2put = j->mgr;
+               }
+               LIST_INSERT_HEAD(&where2put->label_hash[hash_label(nj->label)], nj, label_hash_sle);
+               LIST_INSERT_HEAD(&j->subjobs, nj, subjob_sle);
+       }
+       
+       return nj;
+}
+
 job_t 
 job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv)
 {
 job_t 
 job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv)
 {
@@ -1514,7 +1905,7 @@ job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *arg
                return NULL;
        }
 
                return NULL;
        }
 
-       char *anon_or_legacy = ( label == AUTO_PICK_ANONYMOUS_LABEL ) ? "anonymous" : "mach_init";
+       char *anon_or_legacy = (label == AUTO_PICK_ANONYMOUS_LABEL) ? "anonymous" : "mach_init";
        if (unlikely(label == AUTO_PICK_LEGACY_LABEL || label == AUTO_PICK_ANONYMOUS_LABEL)) {
                if (prog) {
                        bn = prog;
        if (unlikely(label == AUTO_PICK_LEGACY_LABEL || label == AUTO_PICK_ANONYMOUS_LABEL)) {
                if (prog) {
                        bn = prog;
@@ -1527,7 +1918,11 @@ job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *arg
                /* This is so we can do gross things later. See NOTE_EXEC for anonymous jobs */
                minlabel_len = strlen(label) + MAXCOMLEN;
        } else {
                /* This is so we can do gross things later. See NOTE_EXEC for anonymous jobs */
                minlabel_len = strlen(label) + MAXCOMLEN;
        } else {
-               minlabel_len = strlen(label);
+               if (label == AUTO_PICK_XPC_LABEL) {
+                       minlabel_len = snprintf(auto_label, sizeof(auto_label), "com.apple.xpc.domain-owner.%s", jm->owner);
+               } else {
+                       minlabel_len = strlen(label);
+               }
        }
 
        j = calloc(1, sizeof(struct job_s) + minlabel_len + 1);
        }
 
        j = calloc(1, sizeof(struct job_s) + minlabel_len + 1);
@@ -1539,7 +1934,7 @@ job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *arg
        if (unlikely(label == auto_label)) {
                snprintf((char *)j->label, strlen(label) + 1, "%p.%s.%s", j, anon_or_legacy, bn);
        } else {
        if (unlikely(label == auto_label)) {
                snprintf((char *)j->label, strlen(label) + 1, "%p.%s.%s", j, anon_or_legacy, bn);
        } else {
-               strcpy((char *)j->label, label);
+               strcpy((char *)j->label, (label == AUTO_PICK_XPC_LABEL) ? auto_label : label);
        }
        j->kqjob_callback = job_callback;
        j->mgr = jm;
        }
        j->kqjob_callback = job_callback;
        j->mgr = jm;
@@ -1551,6 +1946,7 @@ job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *arg
        j->checkedin = true;
        j->jetsam_priority = -1;
        j->jetsam_memlimit = -1;
        j->checkedin = true;
        j->jetsam_priority = -1;
        j->jetsam_memlimit = -1;
+       j->jetsam_seq = -1;
        uuid_clear(j->expected_audit_uuid);
        
        if (prog) {
        uuid_clear(j->expected_audit_uuid);
        
        if (prog) {
@@ -1585,12 +1981,17 @@ job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *arg
                j->argv[i] = NULL;
        }
 
                j->argv[i] = NULL;
        }
 
-       if( strcmp(j->label, "com.apple.WindowServer") == 0 ) {
+       if (strcmp(j->label, "com.apple.WindowServer") == 0) {
                j->has_console = true;
        }
 
        LIST_INSERT_HEAD(&jm->jobs, j, sle);
                j->has_console = true;
        }
 
        LIST_INSERT_HEAD(&jm->jobs, j, sle);
-       LIST_INSERT_HEAD(&label_hash[hash_label(j->label)], j, label_hash_sle);
+       
+       jobmgr_t where2put_label = root_jobmgr;
+       if (j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN) {
+               where2put_label = j->mgr;
+       }
+       LIST_INSERT_HEAD(&where2put_label->label_hash[hash_label(j->label)], j, label_hash_sle);
        uuid_clear(j->expected_audit_uuid);
 
        job_log(j, LOG_DEBUG, "Conceived");
        uuid_clear(j->expected_audit_uuid);
 
        job_log(j, LOG_DEBUG, "Conceived");
@@ -1606,6 +2007,47 @@ out_bad:
        return NULL;
 }
 
        return NULL;
 }
 
+#ifndef __LAUNCH_DISABLE_XPC_SUPPORT__
+job_t
+job_new_alias(jobmgr_t jm, job_t src)
+{
+       job_t j = NULL;
+       if (job_find(jm, src->label)) {
+               errno = EEXIST;
+       } else {
+               j = calloc(1, sizeof(struct job_s) + strlen(src->label) + 1);
+               if (jobmgr_assumes(jm, j != NULL)) {
+                       strcpy((char *)j->label, src->label);
+                       LIST_INSERT_HEAD(&jm->jobs, j, sle);
+                       LIST_INSERT_HEAD(&jm->label_hash[hash_label(j->label)], j, label_hash_sle);
+                       /* Bad jump address. The kqueue callback for aliases should never be
+                        * invoked.
+                        */
+                       j->kqjob_callback = (kq_callback)0xfa1afe1;
+                       j->alias = src;
+                       j->mgr = jm;
+
+                       struct machservice *msi = NULL;
+                       SLIST_FOREACH(msi, &src->machservices, sle) {
+                               if (!machservice_new_alias(j, msi)) {
+                                       jobmgr_log(jm, LOG_ERR, "Failed to alias job: %s", src->label);
+                                       errno = EINVAL;
+                                       job_remove(j);
+                                       j = NULL;
+                                       break;
+                               }
+                       }
+               }
+
+               if (j) {
+                       job_log(j, LOG_DEBUG, "Aliased service into domain: %s", jm->name);
+               }
+       }
+
+       return j;
+}
+#endif
+
 job_t 
 job_import(launch_data_t pload)
 {
 job_t 
 job_import(launch_data_t pload)
 {
@@ -1633,7 +2075,7 @@ job_import_bulk(launch_data_t pload)
        ja = alloca(c * sizeof(job_t));
 
        for (i = 0; i < c; i++) {
        ja = alloca(c * sizeof(job_t));
 
        for (i = 0; i < c; i++) {
-               if( (likely(ja[i] = jobmgr_import2(root_jobmgr, launch_data_array_get_index(pload, i)))) && errno != ENEEDAUTH ) {
+               if ((likely(ja[i] = jobmgr_import2(root_jobmgr, launch_data_array_get_index(pload, i)))) && errno != ENEEDAUTH) {
                        errno = 0;
                }
                launch_data_array_set_index(resp, launch_data_new_errno(errno), i);
                        errno = 0;
                }
                launch_data_array_set_index(resp, launch_data_new_errno(errno), i);
@@ -1662,6 +2104,13 @@ job_import_bool(job_t j, const char *key, bool value)
                        found_key = true;
                }
                break;
                        found_key = true;
                }
                break;
+       case 'b':
+       case 'B':
+               if (strcasecmp(key, LAUNCH_JOBKEY_BEGINTRANSACTIONATSHUTDOWN) == 0) {
+                       j->dirty_at_shutdown = value;
+                       found_key = true;
+               }
+               break;
        case 'k':
        case 'K':
                if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE) == 0) {
        case 'k':
        case 'K':
                if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE) == 0) {
@@ -1682,17 +2131,18 @@ job_import_bool(job_t j, const char *key, bool value)
                        j->debug = value;
                        found_key = true;
                } else if (strcasecmp(key, LAUNCH_JOBKEY_DISABLED) == 0) {
                        j->debug = value;
                        found_key = true;
                } else if (strcasecmp(key, LAUNCH_JOBKEY_DISABLED) == 0) {
-                       job_assumes(j, !value);
+                       (void)job_assumes(j, !value);
+                       found_key = true;
+               } else if (strcasecmp(key, LAUNCH_JOBKEY_DISABLEASLR) == 0) {
+                       j->disable_aslr = value;
                        found_key = true;
                }
                break;
        case 'h':
        case 'H':
                if (strcasecmp(key, LAUNCH_JOBKEY_HOPEFULLYEXITSLAST) == 0) {
                        found_key = true;
                }
                break;
        case 'h':
        case 'H':
                if (strcasecmp(key, LAUNCH_JOBKEY_HOPEFULLYEXITSLAST) == 0) {
-                       j->hopefully_exits_last = value;
-                       found_key = true;
-               } else if (strcasecmp(key, LAUNCH_JOBKEY_HOPEFULLYEXITSFIRST) == 0) {
-                       j->hopefully_exits_first = value;
+                       job_log(j, LOG_INFO, "%s has been deprecated. Please use the new %s key instead and add EnableTransactions to your launchd.plist.", LAUNCH_JOBKEY_HOPEFULLYEXITSLAST, LAUNCH_JOBKEY_BEGINTRANSACTIONATSHUTDOWN);
+                       j->dirty_at_shutdown = value;
                        found_key = true;
                }
                break;
                        found_key = true;
                }
                break;
@@ -1707,6 +2157,14 @@ job_import_bool(job_t j, const char *key, bool value)
                } else if (strcasecmp(key, LAUNCH_JOBKEY_SERVICEIPC) == 0) {
                        /* this only does something on Mac OS X 10.4 "Tiger" */
                        found_key = true;
                } else if (strcasecmp(key, LAUNCH_JOBKEY_SERVICEIPC) == 0) {
                        /* this only does something on Mac OS X 10.4 "Tiger" */
                        found_key = true;
+               } else if (strcasecmp(key, LAUNCH_JOBKEY_SHUTDOWNMONITOR) == 0) {
+                       if (_s_shutdown_monitor) {
+                               job_log(j, LOG_ERR, "Only one job may monitor shutdown.");
+                       } else {
+                               j->shutdown_monitor = true;
+                               _s_shutdown_monitor = j;
+                       }
+                       found_key = true;
                }
                break;
        case 'l':
                }
                break;
        case 'l':
@@ -1724,6 +2182,9 @@ job_import_bool(job_t j, const char *key, bool value)
                if (strcasecmp(key, LAUNCH_JOBKEY_MACHEXCEPTIONHANDLER) == 0) {
                        j->internal_exc_handler = value;
                        found_key = true;
                if (strcasecmp(key, LAUNCH_JOBKEY_MACHEXCEPTIONHANDLER) == 0) {
                        j->internal_exc_handler = value;
                        found_key = true;
+               } else if (strcasecmp(key, LAUNCH_JOBKEY_MULTIPLEINSTANCES) == 0) {
+                       j->multiple_instances = value;
+                       found_key = true;
                }
                break;
        case 'i':
                }
                break;
        case 'i':
@@ -1735,7 +2196,7 @@ job_import_bool(job_t j, const char *key, bool value)
                        }
                        j->no_init_groups = !value;
                        found_key = true;
                        }
                        j->no_init_groups = !value;
                        found_key = true;
-               } else if( strcasecmp(key, LAUNCH_JOBKEY_IGNOREPROCESSGROUPATSHUTDOWN) == 0 ) {
+               } else if (strcasecmp(key, LAUNCH_JOBKEY_IGNOREPROCESSGROUPATSHUTDOWN) == 0) {
                        j->ignore_pg_at_shutdown = value;
                        found_key = true;
                }
                        j->ignore_pg_at_shutdown = value;
                        found_key = true;
                }
@@ -1761,14 +2222,24 @@ job_import_bool(job_t j, const char *key, bool value)
                } else if (strcasecmp(key, LAUNCH_JOBKEY_ENTERKERNELDEBUGGERBEFOREKILL) == 0) {
                        j->debug_before_kill = value;
                        found_key = true;
                } else if (strcasecmp(key, LAUNCH_JOBKEY_ENTERKERNELDEBUGGERBEFOREKILL) == 0) {
                        j->debug_before_kill = value;
                        found_key = true;
-               } else if( strcasecmp(key, LAUNCH_JOBKEY_EMBEDDEDPRIVILEGEDISPENSATION) == 0 ) {
-                       if( !s_embedded_privileged_job ) {
+               } else if (strcasecmp(key, LAUNCH_JOBKEY_EMBEDDEDPRIVILEGEDISPENSATION) == 0) {
+                       if (!s_embedded_privileged_job) {
                                j->embedded_special_privileges = value;
                                s_embedded_privileged_job = j;
                        } else {
                                job_log(j, LOG_ERR, "Job tried to claim %s after it has already been claimed.", key);
                        }
                        found_key = true;
                                j->embedded_special_privileges = value;
                                s_embedded_privileged_job = j;
                        } else {
                                job_log(j, LOG_ERR, "Job tried to claim %s after it has already been claimed.", key);
                        }
                        found_key = true;
+               } else if (strcasecmp(key, LAUNCH_JOBKEY_EVENTMONITOR) == 0) {
+                       if (job_assumes(j, _s_event_monitor == NULL)) {
+                               j->event_monitor = value;
+                               if (value) {
+                                       _s_event_monitor = j;
+                               }
+                       } else {
+                               job_log(j, LOG_NOTICE, "Job tried to steal event monitoring responsibility!");
+                       }
+                       found_key = true;
                }
                break;
        case 'w':
                }
                break;
        case 'w':
@@ -1803,6 +2274,21 @@ job_import_string(job_t j, const char *key, const char *value)
        case 'P':
                if (strcasecmp(key, LAUNCH_JOBKEY_PROGRAM) == 0) {
                        return;
        case 'P':
                if (strcasecmp(key, LAUNCH_JOBKEY_PROGRAM) == 0) {
                        return;
+               } else if (strcasecmp(key, LAUNCH_JOBKEY_POSIXSPAWNTYPE) == 0) {
+                       if (strcasecmp(value, LAUNCH_KEY_POSIXSPAWNTYPE_TALAPP) == 0) {
+                               j->pstype = POSIX_SPAWN_OSX_TALAPP_START;
+                       } else if (strcasecmp(value, LAUNCH_KEY_POSIXSPAWNTYPE_WIDGET) == 0) {
+                               j->pstype = POSIX_SPAWN_OSX_WIDGET_START;
+                       }
+#if TARGET_OS_EMBEDDED
+                       else if (strcasecmp(value, LAUNCH_KEY_POSIXSPAWNTYPE_IOSAPP) == 0) {
+                               j->pstype = POSIX_SPAWN_IOS_APP_START;
+                       }
+#endif
+                       else {
+                               job_log(j, LOG_ERR, "Unknown value for key %s: %s", key, value);
+                       }
+                       return;
                }
                break;
        case 'l':
                }
                break;
        case 'l':
@@ -1868,9 +2354,9 @@ job_import_string(job_t j, const char *key, const char *value)
                        j->stdin_fd = _fd(open(value, O_RDONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, DEFFILEMODE));
                        if (job_assumes(j, j->stdin_fd != -1)) {
                                /* open() should not block, but regular IO by the job should */
                        j->stdin_fd = _fd(open(value, O_RDONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, DEFFILEMODE));
                        if (job_assumes(j, j->stdin_fd != -1)) {
                                /* open() should not block, but regular IO by the job should */
-                               job_assumes(j, fcntl(j->stdin_fd, F_SETFL, 0) != -1);
+                               (void)job_assumes(j, fcntl(j->stdin_fd, F_SETFL, 0) != -1);
                                /* XXX -- EV_CLEAR should make named pipes happy? */
                                /* XXX -- EV_CLEAR should make named pipes happy? */
-                               job_assumes(j, kevent_mod(j->stdin_fd, EVFILT_READ, EV_ADD|EV_CLEAR, 0, 0, j) != -1);
+                               (void)job_assumes(j, kevent_mod(j->stdin_fd, EVFILT_READ, EV_ADD|EV_CLEAR, 0, 0, j) != -1);
                        } else {
                                j->stdin_fd = 0;
                        }
                        } else {
                                j->stdin_fd = 0;
                        }
@@ -1880,16 +2366,22 @@ job_import_string(job_t j, const char *key, const char *value)
 #endif
                }
                break;
 #endif
                }
                break;
+       case 'X':
+       case 'x':
+               if (strcasecmp(key, LAUNCH_JOBKEY_XPCDOMAIN) == 0) {
+                       return;
+               }
+               break;
        default:
                job_log(j, LOG_WARNING, "Unknown key for string: %s", key);
                break;
        }
 
        if (likely(where2put)) {
        default:
                job_log(j, LOG_WARNING, "Unknown key for string: %s", key);
                break;
        }
 
        if (likely(where2put)) {
-               job_assumes(j, (*where2put = strdup(value)) != NULL);
+               (void)job_assumes(j, (*where2put = strdup(value)) != NULL);
        } else {
                /* See rdar://problem/5496612. These two are okay. */
        } else {
                /* See rdar://problem/5496612. These two are okay. */
-               if( strncmp(key, "SHAuthorizationRight", sizeof("SHAuthorizationRight")) != 0 && strncmp(key, "ServiceDescription", sizeof("ServiceDescription")) != 0 ) {
+               if (strncmp(key, "SHAuthorizationRight", sizeof("SHAuthorizationRight")) != 0 && strncmp(key, "ServiceDescription", sizeof("ServiceDescription")) != 0) {
                        job_log(j, LOG_WARNING, "Unknown key: %s", key);
                }
        }
                        job_log(j, LOG_WARNING, "Unknown key: %s", key);
                }
        }
@@ -1909,17 +2401,17 @@ job_import_integer(job_t j, const char *key, long long value)
                        } else {
                                j->exit_timeout = (typeof(j->exit_timeout)) value;
                        }
                        } else {
                                j->exit_timeout = (typeof(j->exit_timeout)) value;
                        }
-               } else if( strcasecmp(key, LAUNCH_JOBKEY_EMBEDDEDMAINTHREADPRIORITY) == 0 ) {
+               } else if (strcasecmp(key, LAUNCH_JOBKEY_EMBEDDEDMAINTHREADPRIORITY) == 0) {
                        j->main_thread_priority = value;
                }
                break;
        case 'j':
        case 'J':
                        j->main_thread_priority = value;
                }
                break;
        case 'j':
        case 'J':
-               if( strcasecmp(key, LAUNCH_JOBKEY_JETSAMPRIORITY) == 0 ) {
+               if (strcasecmp(key, LAUNCH_JOBKEY_JETSAMPRIORITY) == 0) {
                        job_log(j, LOG_WARNING | LOG_CONSOLE, "Please change the JetsamPriority key to be in a dictionary named JetsamProperties.");
                        
                        launch_data_t pri = launch_data_new_integer(value);
                        job_log(j, LOG_WARNING | LOG_CONSOLE, "Please change the JetsamPriority key to be in a dictionary named JetsamProperties.");
                        
                        launch_data_t pri = launch_data_new_integer(value);
-                       if( job_assumes(j, pri != NULL) ) {
+                       if (job_assumes(j, pri != NULL)) {
                                jetsam_property_setup(pri, LAUNCH_JOBKEY_JETSAMPRIORITY, j);
                                launch_data_free(pri);
                        }
                                jetsam_property_setup(pri, LAUNCH_JOBKEY_JETSAMPRIORITY, j);
                                launch_data_free(pri);
                        }
@@ -1975,7 +2467,7 @@ job_import_integer(job_t j, const char *key, long long value)
                                runtime_add_weak_ref();
                                j->start_interval = (typeof(j->start_interval)) value;
 
                                runtime_add_weak_ref();
                                j->start_interval = (typeof(j->start_interval)) value;
 
-                               job_assumes(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, j->start_interval, j) != -1);
+                               (void)job_assumes(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, j->start_interval, j) != -1);
                        }
 #if HAVE_SANDBOX
                } else if (strcasecmp(key, LAUNCH_JOBKEY_SANDBOXFLAGS) == 0) {
                        }
 #if HAVE_SANDBOX
                } else if (strcasecmp(key, LAUNCH_JOBKEY_SANDBOXFLAGS) == 0) {
@@ -2009,9 +2501,9 @@ job_import_opaque(job_t j __attribute__((unused)),
 #endif
        case 's':
        case 'S':
 #endif
        case 's':
        case 'S':
-               if( strcasecmp(key, LAUNCH_JOBKEY_SECURITYSESSIONUUID) == 0 ) {
+               if (strcasecmp(key, LAUNCH_JOBKEY_SECURITYSESSIONUUID) == 0) {
                        size_t tmpsz = launch_data_get_opaque_size(value);
                        size_t tmpsz = launch_data_get_opaque_size(value);
-                       if( job_assumes(j, tmpsz == sizeof(uuid_t)) ) {
+                       if (job_assumes(j, tmpsz == sizeof(uuid_t))) {
                                memcpy(j->expected_audit_uuid, launch_data_get_opaque(value), sizeof(uuid_t));
                        }
                }
                                memcpy(j->expected_audit_uuid, launch_data_get_opaque(value), sizeof(uuid_t));
                        }
                }
@@ -2074,7 +2566,7 @@ job_import_dictionary(job_t j, const char *key, launch_data_t value)
                break;
        case 'j':
        case 'J':
                break;
        case 'j':
        case 'J':
-               if( strcasecmp(key, LAUNCH_JOBKEY_JETSAMPROPERTIES) == 0 ) {
+               if (strcasecmp(key, LAUNCH_JOBKEY_JETSAMPROPERTIES) == 0) {
                        launch_data_dict_iterate(value, (void (*)(launch_data_t, const char *, void *))jetsam_property_setup, j);
                }
        case 'e':
                        launch_data_dict_iterate(value, (void (*)(launch_data_t, const char *, void *))jetsam_property_setup, j);
                }
        case 'e':
@@ -2119,6 +2611,19 @@ job_import_dictionary(job_t j, const char *key, launch_data_t value)
                        launch_data_dict_iterate(value, machservice_setup, j);
                }
                break;
                        launch_data_dict_iterate(value, machservice_setup, j);
                }
                break;
+       case 'l':
+       case 'L':
+               if (strcasecmp(key, LAUNCH_JOBKEY_LAUNCHEVENTS) == 0) {
+                       launch_data_dict_iterate(value, eventsystem_setup, j);
+               } else {
+                       if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADTOHARDWARE) == 0) {
+                               return;
+                       }
+                       if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADFROMHARDWARE) == 0) {
+                               return;
+                       }
+               }
+               break;
        default:
                job_log(j, LOG_WARNING, "Unknown key for dictionary: %s", key);
                break;
        default:
                job_log(j, LOG_WARNING, "Unknown key for dictionary: %s", key);
                break;
@@ -2236,7 +2741,7 @@ job_import_keys(launch_data_t obj, const char *key, void *context)
        }
 }
 
        }
 }
 
-job_t 
+job_t
 jobmgr_import2(jobmgr_t jm, launch_data_t pload)
 {
        launch_data_t tmp, ldpa;
 jobmgr_import2(jobmgr_t jm, launch_data_t pload)
 {
        launch_data_t tmp, ldpa;
@@ -2270,30 +2775,30 @@ jobmgr_import2(jobmgr_t jm, launch_data_t pload)
        }
 
 #if TARGET_OS_EMBEDDED
        }
 
 #if TARGET_OS_EMBEDDED
-       if( unlikely(g_embedded_privileged_action && s_embedded_privileged_job) ) {
-               if( unlikely(!(tmp = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_USERNAME))) ) {
+       if (unlikely(g_embedded_privileged_action && s_embedded_privileged_job)) {
+               if (unlikely(!(tmp = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_USERNAME)))) {
                        errno = EPERM;
                        return NULL;
                }
                
                const char *username = NULL;
                        errno = EPERM;
                        return NULL;
                }
                
                const char *username = NULL;
-               if( likely(tmp && launch_data_get_type(tmp) == LAUNCH_DATA_STRING) ) {
+               if (likely(tmp && launch_data_get_type(tmp) == LAUNCH_DATA_STRING)) {
                        username = launch_data_get_string(tmp);
                } else {
                        errno = EPERM;
                        return NULL;
                }
                
                        username = launch_data_get_string(tmp);
                } else {
                        errno = EPERM;
                        return NULL;
                }
                
-               if( !jobmgr_assumes(jm, s_embedded_privileged_job->username != NULL && username != NULL) ) {
+               if (!jobmgr_assumes(jm, s_embedded_privileged_job->username != NULL && username != NULL)) {
                        errno = EPERM;
                        return NULL;
                }
                
                        errno = EPERM;
                        return NULL;
                }
                
-               if( unlikely(strcmp(s_embedded_privileged_job->username, username) != 0) ) {
+               if (unlikely(strcmp(s_embedded_privileged_job->username, username) != 0)) {
                        errno = EPERM;
                        return NULL;
                }
                        errno = EPERM;
                        return NULL;
                }
-       } else if( g_embedded_privileged_action ) {
+       } else if (g_embedded_privileged_action) {
                errno = EINVAL;
                return NULL;
        }
                errno = EINVAL;
                return NULL;
        }
@@ -2304,6 +2809,7 @@ jobmgr_import2(jobmgr_t jm, launch_data_t pload)
                prog = launch_data_get_string(tmp);
        }
 
                prog = launch_data_get_string(tmp);
        }
 
+       int argc = 0;
        if ((ldpa = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_PROGRAMARGUMENTS))) {
                size_t i, c;
 
        if ((ldpa = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_PROGRAMARGUMENTS))) {
                size_t i, c;
 
@@ -2328,27 +2834,68 @@ jobmgr_import2(jobmgr_t jm, launch_data_t pload)
                }
 
                argv[i] = NULL;
                }
 
                argv[i] = NULL;
+               argc = i;
        }
 
        }
 
-       /* Hack to make sure the proper job manager is set the whole way through. */
+       if (!prog && argc == 0) {
+               jobmgr_log(jm, LOG_ERR, "Job specifies neither Program nor ProgramArguments: %s", label);
+               errno = EINVAL;
+               return NULL;
+       }
+
+       /* Find the requested session. You cannot load services into XPC domains in
+        * this manner.
+        */
        launch_data_t session = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE);
        launch_data_t session = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE);
-       if( session ) {
-               jm = jobmgr_find_by_name(jm, launch_data_get_string(session)) ?: jm;
+       if (session) {
+               jobmgr_t jmt = NULL;
+               if (launch_data_get_type(session) == LAUNCH_DATA_STRING) {
+                       jmt = jobmgr_find_by_name(jm, launch_data_get_string(session));
+                       if (!jmt) {
+                               jobmgr_log(jm, LOG_ERR, "Could not find requested session: %s", launch_data_get_string(session));
+                       } else {
+                               jm = jmt;
+                       }
+               } else {
+                       jobmgr_log(jm, LOG_ERR, "Session type is not a string.");
+               }
+
+               if (!jmt) {
+                       errno = EINVAL;
+                       return NULL;
+               }
        }
        }
-       
-       jobmgr_log(jm, LOG_DEBUG, "Importing %s.", label);
-       
-       if (unlikely((j = job_find(label)) != NULL)) {
-               errno = EEXIST;
-               return NULL;
-       } else if (unlikely(!jobmgr_label_test(jm, label))) {
+
+       /* For legacy reasons, we have a global hash of all labels in all job
+        * managers. So rather than make it a global, we store it in the root job
+        * manager. But for an XPC domain, we store a local hash of all services in
+        * the domain.
+        */
+       jobmgr_t where2look = (jm->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN) ? jm : root_jobmgr;
+       if (unlikely((j = job_find(where2look, label)) != NULL)) {
+               if (jm->xpc_singleton) {
+                       /* There can (and probably will be) multiple attemtps to import the
+                        * same XPC service from the same framework. This is okay. It's
+                        * treated as a singleton, so just return the existing one so that
+                        * it may be aliased into the requesting process' XPC domain.
+                        */
+                       return j;
+               } else {
+                       /* If we're not a global XPC domain, then it's an error to try
+                        * importing the same job/service multiple times.
+                        */
+                       errno = EEXIST;
+                       return NULL;
+               }
+       } else if (unlikely(!jobmgr_label_test(where2look, label))) {
                errno = EINVAL;
                return NULL;
        }
                errno = EINVAL;
                return NULL;
        }
+       jobmgr_log(jm, LOG_DEBUG, "Importing %s.", label);
 
        if (likely(j = job_new(jm, label, prog, argv))) {
                launch_data_dict_iterate(pload, job_import_keys, j);
 
        if (likely(j = job_new(jm, label, prog, argv))) {
                launch_data_dict_iterate(pload, job_import_keys, j);
-               if( !uuid_is_null(j->expected_audit_uuid) ) {
+               if (!uuid_is_null(j->expected_audit_uuid)) {
                        uuid_string_t uuid_str;
                        uuid_unparse(j->expected_audit_uuid, uuid_str);
                        job_log(j, LOG_DEBUG, "Imported job. Waiting for session for UUID %s.", uuid_str);
                        uuid_string_t uuid_str;
                        uuid_unparse(j->expected_audit_uuid, uuid_str);
                        job_log(j, LOG_DEBUG, "Imported job. Waiting for session for UUID %s.", uuid_str);
@@ -2356,7 +2903,30 @@ jobmgr_import2(jobmgr_t jm, launch_data_t pload)
                        errno = ENEEDAUTH;
                } else {
                        job_log(j, LOG_DEBUG, "No security session specified.");
                        errno = ENEEDAUTH;
                } else {
                        job_log(j, LOG_DEBUG, "No security session specified.");
-                       j->audit_session = MACH_PORT_NULL;
+                       j->asport = MACH_PORT_NULL;
+               }
+
+               if (j->event_monitor) {
+                       if (job_assumes(j, LIST_FIRST(&j->events) == NULL)) {
+                               struct machservice *msi = NULL;
+                               SLIST_FOREACH(msi, &j->machservices, sle) {
+                                       if (msi->event_update_port) {
+                                               break;
+                                       }
+                               }
+
+                               if (job_assumes(j, msi != NULL)) {
+                                       /* Create our send-once right so we can kick things off. */
+                                       (void)job_assumes(j, launchd_mport_make_send_once(msi->port, &_s_event_update_port) == KERN_SUCCESS);
+                                       if (!LIST_EMPTY(&_s_event_systems)) {
+                                               eventsystem_ping();
+                                       }
+                               }
+                       } else {
+                               job_log(j, LOG_ERR, "The event monitor job may not have a LaunchEvents dictionary.");
+                               job_remove(j);
+                               j = NULL;
+                       }
                }
        }
 
                }
        }
 
@@ -2398,11 +2968,15 @@ jobmgr_label_test(jobmgr_t jm, const char *str)
 }
 
 job_t 
 }
 
 job_t 
-job_find(const char *label)
+job_find(jobmgr_t jm, const char *label)
 {
        job_t ji;
 {
        job_t ji;
-
-       LIST_FOREACH(ji, &label_hash[hash_label(label)], label_hash_sle) {
+       
+       if (!jm) {
+               jm = root_jobmgr;
+       }
+       
+       LIST_FOREACH(ji, &jm->label_hash[hash_label(label)], label_hash_sle) {
                if (unlikely(ji->removal_pending || ji->mgr->shutting_down)) {
                        continue; /* 5351245 and 5488633 respectively */
                }
                if (unlikely(ji->removal_pending || ji->mgr->shutting_down)) {
                        continue; /* 5351245 and 5488633 respectively */
                }
@@ -2421,15 +2995,15 @@ job_t
 jobmgr_find_by_pid_deep(jobmgr_t jm, pid_t p, bool anon_okay)
 {
        job_t ji = NULL;
 jobmgr_find_by_pid_deep(jobmgr_t jm, pid_t p, bool anon_okay)
 {
        job_t ji = NULL;
-       LIST_FOREACH( ji, &jm->active_jobs[ACTIVE_JOB_HASH(p)], pid_hash_sle ) {
+       LIST_FOREACH(ji, &jm->active_jobs[ACTIVE_JOB_HASH(p)], pid_hash_sle) {
                if (ji->p == p && (!ji->anonymous || (ji->anonymous && anon_okay)) ) {
                        return ji;
                }
        }
 
        jobmgr_t jmi = NULL;
                if (ji->p == p && (!ji->anonymous || (ji->anonymous && anon_okay)) ) {
                        return ji;
                }
        }
 
        jobmgr_t jmi = NULL;
-       SLIST_FOREACH( jmi, &jm->submgrs, sle ) {
-               if( (ji = jobmgr_find_by_pid_deep(jmi, p, anon_okay)) ) {
+       SLIST_FOREACH(jmi, &jm->submgrs, sle) {
+               if ((ji = jobmgr_find_by_pid_deep(jmi, p, anon_okay))) {
                        break;
                }
        }
                        break;
                }
        }
@@ -2487,15 +3061,13 @@ job_mig_intran(mach_port_t p)
        jr = job_mig_intran2(root_jobmgr, p, ldc->pid);
 
        if (!jobmgr_assumes(root_jobmgr, jr != NULL)) {
        jr = job_mig_intran2(root_jobmgr, p, ldc->pid);
 
        if (!jobmgr_assumes(root_jobmgr, jr != NULL)) {
-               int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
-               struct kinfo_proc kp;
-               size_t len = sizeof(kp);
-
-               mib[3] = ldc->pid;
-
-               if (jobmgr_assumes(root_jobmgr, sysctl(mib, 4, &kp, &len, NULL, 0) != -1)
-                               && jobmgr_assumes(root_jobmgr, len == sizeof(kp))) {
-                       jobmgr_log(root_jobmgr, LOG_ERR, "%s() was confused by PID %u UID %u EUID %u Mach Port 0x%x: %s", __func__, ldc->pid, ldc->uid, ldc->euid, p, kp.kp_proc.p_comm);
+               struct proc_bsdshortinfo proc;
+               if (proc_pidinfo(ldc->pid, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
+                       if (errno != ESRCH) {
+                               (void)jobmgr_assumes(root_jobmgr, errno == 0);
+                       } else {
+                               jobmgr_log(root_jobmgr, LOG_ERR, "%s() was confused by PID %u UID %u EUID %u Mach Port 0x%x: %s", __func__, ldc->pid, ldc->uid, ldc->euid, p, proc.pbsi_comm);
+                       }
                }
        }
 
                }
        }
 
@@ -2569,42 +3141,48 @@ job_export_all(void)
 void
 job_log_stray_pg(job_t j)
 {
 void
 job_log_stray_pg(job_t j)
 {
-       int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, j->p };
-       size_t i, kp_cnt, len = sizeof(struct kinfo_proc) * get_kern_max_proc();
-       struct kinfo_proc *kp;
-
+       pid_t *pids = NULL;
+       size_t len = sizeof(pid_t) * get_kern_max_proc();
+       int i = 0, kp_cnt = 0;
+       
        if (!do_apple_internal_logging) {
                return;
        }
 
        runtime_ktrace(RTKT_LAUNCHD_FINDING_STRAY_PG, j->p, 0, 0);
 
        if (!do_apple_internal_logging) {
                return;
        }
 
        runtime_ktrace(RTKT_LAUNCHD_FINDING_STRAY_PG, j->p, 0, 0);
 
-       if (!job_assumes(j, (kp = malloc(len)) != NULL)) {
+       if (!job_assumes(j, (pids = malloc(len)) != NULL)) {
                return;
        }
                return;
        }
-       if (!job_assumes(j, sysctl(mib, 4, kp, &len, NULL, 0) != -1)) {
+       if (!job_assumes(j, (kp_cnt = proc_listpgrppids(j->p, pids, len)) != -1)) {
                goto out;
        }
                goto out;
        }
-
-       kp_cnt = len / sizeof(struct kinfo_proc);
-
+       
        for (i = 0; i < kp_cnt; i++) {
        for (i = 0; i < kp_cnt; i++) {
-               pid_t p_i = kp[i].kp_proc.p_pid;
-               pid_t pp_i = kp[i].kp_eproc.e_ppid;
-               const char *z = (kp[i].kp_proc.p_stat == SZOMB) ? "zombie " : "";
-               const char *n = kp[i].kp_proc.p_comm;
-
+               pid_t p_i = pids[i];
                if (p_i == j->p) {
                        continue;
                } else if (!job_assumes(j, p_i != 0 && p_i != 1)) {
                        continue;
                }
                if (p_i == j->p) {
                        continue;
                } else if (!job_assumes(j, p_i != 0 && p_i != 1)) {
                        continue;
                }
+               
+               struct proc_bsdshortinfo proc;
+               if (proc_pidinfo(p_i, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
+                       if (errno != ESRCH) {
+                               job_assumes(j, errno == 0);
+                       }
+                       continue;
+               }
+               
+               pid_t pp_i = proc.pbsi_ppid;
+               const char *z = (proc.pbsi_status == SZOMB) ? "zombie " : "";
+               const char *n = proc.pbsi_comm;
 
 
-               job_log(j, LOG_WARNING, "Stray %sprocess with PGID equal to this dead job: PID %u PPID %u %s", z, p_i, pp_i, n);
+               job_log(j, LOG_WARNING, "Stray %sprocess with PGID equal to this dead job: PID %u PPID %u PGID %u %s", z, p_i, pp_i, proc.pbsi_pgid, n);
        }
 
 out:
        }
 
 out:
-       free(kp);
+       free(pids);
 }
 
 void
 }
 
 void
@@ -2618,7 +3196,7 @@ job_reap(job_t j)
        job_log(j, LOG_DEBUG, "Reaping");
 
        if (j->shmem) {
        job_log(j, LOG_DEBUG, "Reaping");
 
        if (j->shmem) {
-               job_assumes(j, vm_deallocate(mach_task_self(), (vm_address_t)j->shmem, getpagesize()) == 0);
+               (void)job_assumes(j, vm_deallocate(mach_task_self(), (vm_address_t)j->shmem, getpagesize()) == 0);
                j->shmem = NULL;
        }
 
                j->shmem = NULL;
        }
 
@@ -2631,13 +3209,13 @@ job_reap(job_t j)
                job_log_stdouterr(j); /* one last chance */
 
                if (j->log_redirect_fd) {
                job_log_stdouterr(j); /* one last chance */
 
                if (j->log_redirect_fd) {
-                       job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
+                       (void)job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
                        j->log_redirect_fd = 0;
                }
        }
 
        if (j->fork_fd) {
                        j->log_redirect_fd = 0;
                }
        }
 
        if (j->fork_fd) {
-               job_assumes(j, runtime_close(j->fork_fd) != -1);
+               (void)job_assumes(j, runtime_close(j->fork_fd) != -1);
                j->fork_fd = 0;
        }
 
                j->fork_fd = 0;
        }
 
@@ -2655,28 +3233,40 @@ job_reap(job_t j)
 #ifdef __LP64__
                                job_log(j, LOG_APPLEONLY, "Bug: 5487498");
 #else
 #ifdef __LP64__
                                job_log(j, LOG_APPLEONLY, "Bug: 5487498");
 #else
-                               job_assumes(j, false);
+                               (void)job_assumes(j, false);
 #endif
                        }
                }
 #endif
                        }
                }
-               
-               /*
-                * 5020256
+
+               /* We have to work around one of two kernel bugs here. ptrace(3) may
+                * have abducted the child away from us and reparented it to the tracing
+                * process. If the process then exits, we still get NOTE_EXIT, but we
+                * cannot reap it because the kernel may not have restored the true
+                * parent/child relationship in time.
+                *
+                * See <rdar://problem/5020256>.
                 *
                 *
-                * The current implementation of ptrace() causes the traced process to
-                * be abducted away from the true parent and adopted by the tracer.
+                * The other bug is if the shutdown monitor has suspended a task and not
+                * resumed it before exiting. In this case, the kernel will not clean up
+                * after the shutdown monitor. It will, instead, leave the task
+                * task suspended and not process any pending signals on the event loop
+                * for the task.
                 *
                 *
-                * Once the tracing process relinquishes control, the kernel then
-                * restores the true parent/child relationship.
+                * There are a variety of other kernel bugs that could prevent a process
+                * from exiting, usually having to do with faulty hardware or talking to
+                * misbehaving drivers that mark a thread as uninterruptible and
+                * deadlock/hang before unmarking it as such. So we have to work around
+                * that too.
                 *
                 *
-                * Unfortunately, the wait*() family of APIs is unaware of the temporarily
-                * data structures changes, and they return an error if reality hasn't
-                * been restored by the time they are called.
+                * See <rdar://problem/9284889&9359725>.
                 */
                 */
-               if (!job_assumes(j, wait4(j->p, &status, 0, &ru) != -1)) {
-                       job_log(j, LOG_NOTICE, "Working around 5020256. Assuming the job crashed.");
-
-                       status = W_EXITCODE(0, SIGSEGV);
+               if (j->workaround9359725) {
+                       job_log(j, LOG_NOTICE, "Simulated exit: <rdar://problem/9359725>");
+                       status = W_EXITCODE(-1, SIGSEGV);
+                       memset(&ru, 0, sizeof(ru));
+               } else if (wait4(j->p, &status, 0, &ru) == -1) {
+                       job_log(j, LOG_NOTICE, "Assuming job exited: <rdar://problem/5020256>: %d: %s", errno, strerror(errno));
+                       status = W_EXITCODE(-1, SIGSEGV);
                        memset(&ru, 0, sizeof(ru));
                }
        }
                        memset(&ru, 0, sizeof(ru));
                }
        }
@@ -2687,18 +3277,6 @@ job_reap(job_t j)
        
        LIST_REMOVE(j, pid_hash_sle);
 
        
        LIST_REMOVE(j, pid_hash_sle);
 
-       if (j->wait_reply_port) {
-               job_log(j, LOG_DEBUG, "MPM wait reply being sent");
-               job_assumes(j, job_mig_wait_reply(j->wait_reply_port, 0, status) == 0);
-               j->wait_reply_port = MACH_PORT_NULL;
-       }
-
-       if( j->pending_sample ) {
-               job_log(j, LOG_DEBUG | LOG_CONSOLE, "Job exited before we could sample it.");
-               STAILQ_REMOVE(&j->mgr->pending_samples, j, job_s, pending_samples_sle);
-               j->pending_sample = false;
-       }
-
        if (j->sent_signal_time) {
                uint64_t td_sec, td_usec, td = runtime_get_nanoseconds_since(j->sent_signal_time);
 
        if (j->sent_signal_time) {
                uint64_t td_sec, td_usec, td = runtime_get_nanoseconds_since(j->sent_signal_time);
 
@@ -2726,35 +3304,42 @@ job_reap(job_t j)
        j->ru.ru_nivcsw += ru.ru_nivcsw;
 
        if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
        j->ru.ru_nivcsw += ru.ru_nivcsw;
 
        if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
-               job_log(j, LOG_WARNING, "Exited with exit code: %d", WEXITSTATUS(status));
+               int level = LOG_WARNING;
+               if (!j->did_exec && (j->fail_cnt++ % LAUNCHD_LOG_FAILED_EXEC_FREQ) != 0) {
+                       level = LOG_DEBUG;
+               }
+
+               job_log(j, level, "Exited with code: %d", WEXITSTATUS(status));
+       } else {
+               j->fail_cnt = 0;
        }
 
        if (WIFSIGNALED(status)) {
                int s = WTERMSIG(status);
                if ((SIGKILL == s || SIGTERM == s) && !j->stopped) {
                        job_log(j, LOG_NOTICE, "Exited: %s", strsignal(s));
        }
 
        if (WIFSIGNALED(status)) {
                int s = WTERMSIG(status);
                if ((SIGKILL == s || SIGTERM == s) && !j->stopped) {
                        job_log(j, LOG_NOTICE, "Exited: %s", strsignal(s));
-               } else if( !j->stopped && !j->clean_kill ) {                    
-                       switch( s ) {
-                               /* Signals which indicate a crash. */
-                               case SIGILL             :
-                               case SIGABRT    :
-                               case SIGFPE             :
-                               case SIGBUS             :
-                               case SIGSEGV    :
-                               case SIGSYS             :
-                               /* If the kernel has posted NOTE_EXIT and the signal sent to the process was
-                                * SIGTRAP, assume that it's a crash.
-                                */
-                               case SIGTRAP    :
-                                       j->crashed = true;
-                                       job_log(j, LOG_WARNING, "Job appears to have crashed: %s", strsignal(s));
-                                       break;
-                               default                 :
-                                       job_log(j, LOG_WARNING, "Exited abnormally: %s", strsignal(s));
-                                       break;
+               } else if (!j->stopped && !j->clean_kill) {                     
+                       switch (s) {
+                       /* Signals which indicate a crash. */
+                       case SIGILL:
+                       case SIGABRT:
+                       case SIGFPE:
+                       case SIGBUS:
+                       case SIGSEGV:
+                       case SIGSYS:
+                       /* If the kernel has posted NOTE_EXIT and the signal sent to the process was
+                        * SIGTRAP, assume that it's a crash.
+                        */
+                       case SIGTRAP:
+                               j->crashed = true;
+                               job_log(j, LOG_WARNING, "Job appears to have crashed: %s", strsignal(s));
+                               break;
+                       default:
+                               job_log(j, LOG_WARNING, "Exited abnormally: %s", strsignal(s));
+                               break;
                        }
                        
                        }
                        
-                       if( is_system_bootstrapper && j->crashed ) {
+                       if (is_system_bootstrapper && j->crashed) {
                                job_log(j, LOG_ERR | LOG_CONSOLE, "The %s bootstrapper has crashed: %s", j->mgr->name, strsignal(s));
                        }
                }
                                job_log(j, LOG_ERR | LOG_CONSOLE, "The %s bootstrapper has crashed: %s", j->mgr->name, strsignal(s));
                        }
                }
@@ -2763,23 +3348,39 @@ job_reap(job_t j)
        j->reaped = true;
        
        struct machservice *msi = NULL;
        j->reaped = true;
        
        struct machservice *msi = NULL;
-       if( j->crashed || !(j->did_exec || j->anonymous) ) {
-               SLIST_FOREACH( msi, &j->machservices, sle ) {
-                       if( j->crashed && !msi->isActive && (msi->drain_one_on_crash || msi->drain_all_on_crash) ) {
+       if (j->crashed || !(j->did_exec || j->anonymous)) {
+               SLIST_FOREACH(msi, &j->machservices, sle) {
+                       if (j->crashed && !msi->isActive && (msi->drain_one_on_crash || msi->drain_all_on_crash)) {
                                machservice_drain_port(msi);
                        }
                        
                                machservice_drain_port(msi);
                        }
                        
-                       if( !j->did_exec && msi->reset && job_assumes(j, !msi->isActive) ) {
+                       if (!j->did_exec && msi->reset && job_assumes(j, !msi->isActive)) {
                                machservice_resetport(j, msi);
                        }
                }
        }
                                machservice_resetport(j, msi);
                        }
                }
        }
-       
+
+       /* HACK: Essentially duplicating the logic directly above. But this has
+        * gotten really hairy, and I don't want to try consolidating it right now.
+        */
+       if (j->xpc_service && !j->xpcproxy_did_exec) {
+               job_log(j, LOG_ERR, "XPC Service could not exec(3). Resetting port.");
+               SLIST_FOREACH(msi, &j->machservices, sle) {
+                       /* Drain the messages but do not reset the port. If xpcproxy could
+                        * not exec(3), then we don't want to continue trying, since there
+                        * is very likely a serious configuration error with the service.
+                        *
+                        * <rdar://problem/8986802>
+                        */
+                       machservice_resetport(j, msi);
+               }
+       }
+
        struct suspended_peruser *spi = NULL;
        struct suspended_peruser *spi = NULL;
-       while( (spi = LIST_FIRST(&j->suspended_perusers)) ) {
+       while ((spi = LIST_FIRST(&j->suspended_perusers))) {
                job_log(j, LOG_ERR, "Job exited before resuming per-user launchd for UID %u. Will forcibly resume.", spi->j->mach_uid);
                spi->j->peruser_suspend_count--;
                job_log(j, LOG_ERR, "Job exited before resuming per-user launchd for UID %u. Will forcibly resume.", spi->j->mach_uid);
                spi->j->peruser_suspend_count--;
-               if( spi->j->peruser_suspend_count == 0 ) {
+               if (spi->j->peruser_suspend_count == 0) {
                        job_dispatch(spi->j, false);
                }
                LIST_REMOVE(spi, sle);
                        job_dispatch(spi->j, false);
                }
                LIST_REMOVE(spi, sle);
@@ -2787,14 +3388,39 @@ job_reap(job_t j)
        }
 
        j->last_exit_status = status;
        }
 
        j->last_exit_status = status;
-       struct waiting_for_exit *w4e = NULL;
-       while( (w4e = LIST_FIRST(&j->exit_watchers)) ) {
-               waiting4exit_delete(j, w4e);
+
+       if (j->exit_status_dest) {
+               errno = helper_downcall_wait(j->exit_status_dest, j->last_exit_status);
+               if (errno && errno != MACH_SEND_INVALID_DEST) {
+                       (void)job_assumes(j, errno == 0);
+               }
+
+               j->exit_status_dest = MACH_PORT_NULL;
        }
        }
-       
+
+       if (j->spawn_reply_port) {
+               /* If the child never called exec(3), we must send a spawn() reply so
+                * that the requestor can get exit status from it. If we fail to send
+                * the reply for some reason, we have to deallocate the exit status port
+                * ourselves.
+                */
+               kern_return_t kr = job_mig_spawn2_reply(j->spawn_reply_port, BOOTSTRAP_SUCCESS, j->p, j->exit_status_port);
+               if (kr) {
+                       if (kr != MACH_SEND_INVALID_DEST) {
+                               errno = kr;
+                               (void)job_assumes(j, errno == KERN_SUCCESS);
+                       }
+
+                       (void)job_assumes(j, launchd_mport_close_recv(j->exit_status_port) == KERN_SUCCESS);
+               }
+
+               j->exit_status_port = MACH_PORT_NULL;
+               j->spawn_reply_port = MACH_PORT_NULL;
+       }
+
        if (j->anonymous) {
                total_anon_children--;
        if (j->anonymous) {
                total_anon_children--;
-               if( j->holds_ref ) {
+               if (j->holds_ref) {
                        runtime_del_ref();
                }
        } else {
                        runtime_del_ref();
                }
        } else {
@@ -2802,29 +3428,44 @@ job_reap(job_t j)
                total_children--;
        }
        
                total_children--;
        }
        
-       if( j->has_console ) {
+       if (j->has_console) {
                g_wsp = 0;
        }
                g_wsp = 0;
        }
+
+       if (j->shutdown_monitor) {
+               job_log(j, LOG_NOTICE | LOG_CONSOLE, "Shutdown monitor has exited.");
+               _s_shutdown_monitor = NULL;
+               j->shutdown_monitor = false;
+       }
+
+       if (j->event_monitor && !j->mgr->shutting_down) {
+               msi = NULL;
+               SLIST_FOREACH(msi, &j->machservices, sle) {
+                       if (msi->event_update_port) {
+                               break;
+                       }
+               }
+               /* Only do this if we've gotten the port-destroyed notification already.
+                * If we haven't yet, the port destruction handler will do this.
+                */
+               if (job_assumes(j, msi != NULL) && !msi->isActive) {
+                       if (_s_event_update_port == MACH_PORT_NULL) {
+                               (void)job_assumes(j, launchd_mport_make_send_once(msi->port, &_s_event_update_port) == KERN_SUCCESS);
+                       }
+                       eventsystem_ping();
+               }
+       }
        
        
-       if (j->hopefully_exits_first) {
-               j->mgr->hopefully_first_cnt--;
-       } else if (!j->anonymous && !j->hopefully_exits_last) {
+       if (!j->anonymous) {
                j->mgr->normal_active_cnt--;
        }
        j->sent_signal_time = 0;
        j->sent_sigkill = false;
        j->clean_kill = false;
                j->mgr->normal_active_cnt--;
        }
        j->sent_signal_time = 0;
        j->sent_sigkill = false;
        j->clean_kill = false;
-       j->sampling_complete = false;
        j->sent_kill_via_shmem = false;
        j->lastlookup = NULL;
        j->lastlookup_gennum = 0;
        j->p = 0;
        j->sent_kill_via_shmem = false;
        j->lastlookup = NULL;
        j->lastlookup_gennum = 0;
        j->p = 0;
-
-       /*
-        * We need to someday evaluate other jobs and find those who wish to track the
-        * active/inactive state of this job. The current job_dispatch() logic makes
-        * this messy, given that jobs can be deleted at dispatch.
-        */
 }
 
 void
 }
 
 void
@@ -2850,158 +3491,26 @@ jobmgr_dispatch_all(jobmgr_t jm, bool newmounthack)
        }
 }
 
        }
 }
 
-pid_t
-basic_spawn(job_t j, void (*what_to_do)(job_t))
-{
-       pid_t p = 0;
-       thread_state_flavor_t f = 0;
-#if defined (__ppc__) || defined(__ppc64__)
-       f = PPC_THREAD_STATE64;
-#elif defined(__i386__) || defined(__x86_64__)
-       f = x86_THREAD_STATE;
-#elif defined(__arm__)
-       f = ARM_THREAD_STATE;
-#else
-       #error "unknown architecture"
-#endif
-       
-       int execpair[2] = { 0, 0 };
-       job_assumes(j, socketpair(AF_UNIX, SOCK_STREAM, 0, execpair) != -1);
-       
-       switch( (p = fork()) ) {
-               case 0  :
-                       job_assumes(j, runtime_close(execpair[0]) != -1);
-                       /* Wait for the parent to attach a kevent. */
-                       read(_fd(execpair[1]), &p, sizeof(p));
-                       what_to_do(j);
-                       _exit(EXIT_FAILURE);
-               case -1 :
-                       job_assumes(j, runtime_close(execpair[0]) != -1);
-                       job_assumes(j, runtime_close(execpair[1]) != -1);
-                       execpair[0] = -1;
-                       execpair[1] = -1;
-                       job_log(j, LOG_NOTICE | LOG_CONSOLE, "fork(2) failed: %d", errno);
-                       break;
-               default :
-                       job_assumes(j, runtime_close(execpair[1]) != -1);
-                       execpair[1] = -1;
-                       break;
-       }
-       
-       int r = -1;
-       if( p != -1 ) {
-               /* Let us know when sample is done. ONESHOT is implicit if we're just interested in NOTE_EXIT. */
-               if( job_assumes(j, (r = kevent_mod(p, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, j)) != -1) ) {
-                       if( !job_assumes(j, write(execpair[0], &p, sizeof(p)) == sizeof(p)) ) {
-                               job_assumes(j, kevent_mod(p, EVFILT_PROC, EV_DELETE, 0, 0, NULL) != -1);
-                               job_assumes(j, runtime_kill(p, SIGKILL) != -1);
-                               r = -1;
-                               p = -1;
-                       }
-               } else {
-                       job_assumes(j, runtime_kill(p, SIGKILL) != -1);
-               }
-               
-               int status = 0;
-               if( r == -1 ) {
-                       job_assumes(j, waitpid(p, &status, WNOHANG) != -1);
-               }
-       }
-       
-       if( execpair[0] != -1 ) {
-               job_assumes(j, runtime_close(execpair[0]) != -1);
-       }
-       
-       if( execpair[1] != -1 ) {
-               job_assumes(j, runtime_close(execpair[0]) != -1);
-       }
-       
-       return p;
-}
-
-void 
-take_sample(job_t j)
-{
-       char pidstr[32];
-       snprintf(pidstr, sizeof(pidstr), "%u", j->p);
-#if !TARGET_OS_EMBEDDED
-       /* -nodsyms so sample doesn't try to use Spotlight to find dsym files after mds has gone away. */
-       char *sample_args[] = { "/usr/bin/sample", pidstr, "1", "-unsupportedShowArch", "-mayDie", "-nodsyms", "-file", j->mgr->sample_log_file, NULL };
-#else
-       char *sample_args[] = { "/usr/bin/sample", pidstr, "1", "-unsupportedShowArch", "-mayDie", "-file", j->mgr->sample_log_file, NULL };
-#endif
-       
-       execve(sample_args[0], sample_args, environ);
-       _exit(EXIT_FAILURE);
-}
-
-void 
-jobmgr_dequeue_next_sample(jobmgr_t jm)
-{
-       if( STAILQ_EMPTY(&jm->pending_samples) ) {
-               jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Sample queue is empty.");
-               return;
-       }
-       
-       /* Dequeue the next in line. */
-       job_t j = STAILQ_FIRST(&jm->pending_samples);
-       if( j->is_being_sampled ) {
-               job_log(j, LOG_DEBUG | LOG_CONSOLE, "Sampling is in progress. Not dequeuing next job.");
-               return;
-       }
-
-       if( !job_assumes(j, !j->sampling_complete) ) {
-               return;
-       }
-
-       if (!job_assumes(j, do_apple_internal_logging)) {
-               return;
-       }
-
-       if (!job_assumes(j, mkdir(SHUTDOWN_LOG_DIR, S_IRWXU) != -1 || errno == EEXIST)) {
-               return;
-       }
-
-       char pidstr[32];
-       snprintf(pidstr, sizeof(pidstr), "%u", j->p);
-       snprintf(j->mgr->sample_log_file, sizeof(j->mgr->sample_log_file), SHUTDOWN_LOG_DIR "/%s-%u.sample.txt", j->label, j->p);
-       
-       if (job_assumes(j, unlink(jm->sample_log_file) != -1 || errno == ENOENT)) {
-               pid_t sp = basic_spawn(j, take_sample);
-               
-               if( sp == -1 ) {
-                       job_log(j, LOG_ERR | LOG_CONSOLE, "Sampling for job failed!");
-                       STAILQ_REMOVE(&jm->pending_samples, j, job_s, pending_samples_sle);
-                       j->sampling_complete = true;
-                       jobmgr_dequeue_next_sample(jm);
-               } else {
-                       j->tracing_pid = sp;
-                       j->is_being_sampled = true;
-                       job_log(j, LOG_DEBUG | LOG_CONSOLE, "Sampling job (sample PID: %i, file: %s).", sp, j->mgr->sample_log_file);
-               }
-       } else {
-               STAILQ_REMOVE(&jm->pending_samples, j, job_s, pending_samples_sle);
-               j->sampling_complete = true;
-       }
-       
-       j->pending_sample = false;
-}
-
 void
 job_dispatch_curious_jobs(job_t j)
 {      
        job_t ji = NULL, jt = NULL;
 void
 job_dispatch_curious_jobs(job_t j)
 {      
        job_t ji = NULL, jt = NULL;
-       SLIST_FOREACH_SAFE( ji, &s_curious_jobs, curious_jobs_sle, jt ) {
+       SLIST_FOREACH_SAFE(ji, &s_curious_jobs, curious_jobs_sle, jt) {
                struct semaphoreitem *si = NULL;
                struct semaphoreitem *si = NULL;
-               SLIST_FOREACH( si, &ji->semaphores, sle ) {                     
-                       if( !(si->why == OTHER_JOB_ENABLED || si->why == OTHER_JOB_DISABLED) ) {
+               SLIST_FOREACH(si, &ji->semaphores, sle) {                       
+                       if (!(si->why == OTHER_JOB_ENABLED || si->why == OTHER_JOB_DISABLED)) {
                                continue;
                        }
                        
                                continue;
                        }
                        
-                       if( strncmp(si->what, j->label, strlen(j->label)) == 0 ) {
+                       if (strcmp(si->what, j->label) == 0) {
                                job_log(ji, LOG_DEBUG, "Dispatching out of interest in \"%s\".", j->label);
                                
                                job_log(ji, LOG_DEBUG, "Dispatching out of interest in \"%s\".", j->label);
                                
-                               job_dispatch(ji, false);
+                               if (!ji->removing) {
+                                       job_dispatch(ji, false);
+                               } else {
+                                       job_log(ji, LOG_NOTICE, "The following job is circularly dependent upon this one: %s", j->label);
+                               }
+                               
                                /* ji could be removed here, so don't do anything with it or its semaphores
                                 * after this point.
                                 */
                                /* ji could be removed here, so don't do anything with it or its semaphores
                                 * after this point.
                                 */
@@ -3015,22 +3524,25 @@ job_t
 job_dispatch(job_t j, bool kickstart)
 {
        /* Don't dispatch a job if it has no audit session set. */
 job_dispatch(job_t j, bool kickstart)
 {
        /* Don't dispatch a job if it has no audit session set. */
-       if( !uuid_is_null(j->expected_audit_uuid) ) {
+       if (!uuid_is_null(j->expected_audit_uuid)) {
                return NULL;
        }
                return NULL;
        }
+       if (j->alias) {
+               j = j->alias;
+       }
 
 #if TARGET_OS_EMBEDDED
 
 #if TARGET_OS_EMBEDDED
-       if( g_embedded_privileged_action && s_embedded_privileged_job ) {
-               if( !job_assumes(j, s_embedded_privileged_job->username != NULL && j->username != NULL) ) {
+       if (g_embedded_privileged_action && s_embedded_privileged_job) {
+               if (!job_assumes(j, s_embedded_privileged_job->username != NULL && j->username != NULL)) {
                        errno = EPERM;
                        return NULL;
                }
        
                        errno = EPERM;
                        return NULL;
                }
        
-               if( strcmp(j->username, s_embedded_privileged_job->username) != 0 ) {
+               if (strcmp(j->username, s_embedded_privileged_job->username) != 0) {
                        errno = EPERM;
                        return NULL;
                }
                        errno = EPERM;
                        return NULL;
                }
-       } else if( g_embedded_privileged_action ) {
+       } else if (g_embedded_privileged_action) {
                errno = EINVAL;
                return NULL;
        }
                errno = EINVAL;
                return NULL;
        }
@@ -3049,7 +3561,7 @@ job_dispatch(job_t j, bool kickstart)
                        job_remove(j);
                        return NULL;
                }
                        job_remove(j);
                        return NULL;
                }
-               if( unlikely(j->per_user && j->peruser_suspend_count > 0) ) {
+               if (unlikely(j->per_user && j->peruser_suspend_count > 0)) {
                        return NULL;
                }
                
                        return NULL;
                }
                
@@ -3107,7 +3619,7 @@ job_log_stdouterr(job_t j)
                job_log(j, LOG_DEBUG, "Standard out/error pipe closed");
                close_log_redir = true;
        } else if (rsz == -1) {
                job_log(j, LOG_DEBUG, "Standard out/error pipe closed");
                close_log_redir = true;
        } else if (rsz == -1) {
-               if( !job_assumes(j, errno == EAGAIN) ) {
+               if (!job_assumes(j, errno == EAGAIN)) {
                        close_log_redir = true;
                }
        } else {
                        close_log_redir = true;
                }
        } else {
@@ -3123,7 +3635,7 @@ job_log_stdouterr(job_t j)
        free(buf);
 
        if (unlikely(close_log_redir)) {
        free(buf);
 
        if (unlikely(close_log_redir)) {
-               job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
+               (void)job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
                j->log_redirect_fd = 0;
                job_dispatch(j, false);
        }
                j->log_redirect_fd = 0;
                job_dispatch(j, false);
        }
@@ -3136,105 +3648,99 @@ job_kill(job_t j)
                return;
        }
 
                return;
        }
 
-       job_assumes(j, runtime_kill(j->p, SIGKILL) != -1);
+       (void)job_assumes(j, runtime_kill(j->p, SIGKILL) != -1);
 
        j->sent_sigkill = true;
 
        j->sent_sigkill = true;
-
-       intptr_t timer = j->clean_kill ? LAUNCHD_CLEAN_KILL_TIMER : LAUNCHD_SIGKILL_TIMER;
-       job_assumes(j, kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, timer, j) != -1);
+       (void)job_assumes(j, kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, LAUNCHD_SIGKILL_TIMER, j) != -1);
 
        job_log(j, LOG_DEBUG, "Sent SIGKILL signal");
 }
 
 void
 
        job_log(j, LOG_DEBUG, "Sent SIGKILL signal");
 }
 
 void
-job_log_children_without_exec(job_t j)
+job_open_shutdown_transaction(job_t j)
 {
 {
-       /* <rdar://problem/5701343> ER: Add a KERN_PROC_PPID sysctl */
-#ifdef KERN_PROC_PPID
-       int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PPID, j->p };
-#else
-       int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
-#endif
-       size_t mib_sz = sizeof(mib) / sizeof(mib[0]);
-       size_t i, kp_cnt, len = sizeof(struct kinfo_proc) * get_kern_max_proc();
-       struct kinfo_proc *kp;
+       if (j->kill_via_shmem) {
+               if (j->shmem) {
+                       job_log(j, LOG_DEBUG, "Opening shutdown transaction for job.");
+                       (void)__sync_add_and_fetch(&j->shmem->vp_shmem_transaction_cnt, 1);
+               } else {
+                       job_log(j, LOG_DEBUG, "Job wants to be dirty at shutdown, but it has not set up shared memory. Treating normally.");
+                       j->dirty_at_shutdown = false;
+               }
+       } else {
+               job_log(j, LOG_DEBUG, "Job wants to be dirty at shutdown, but it is not Instant Off-compliant. Treating normally.");
+               j->dirty_at_shutdown = false;
+       }
+}
+
+void
+job_close_shutdown_transaction(job_t j)
+{
+       if (j->dirty_at_shutdown) {
+               job_log(j, LOG_DEBUG, "Closing shutdown transaction for job.");
+               if (__sync_sub_and_fetch(&j->shmem->vp_shmem_transaction_cnt, 1) == -1) {
+                       job_log(j, LOG_DEBUG, "Job is now clean. Killing.");
+                       job_kill(j);
+               }
+               j->dirty_at_shutdown = false;
+       }
+}
 
 
+void
+job_log_children_without_exec(job_t j)
+{
+       pid_t *pids = NULL;
+       size_t len = sizeof(pid_t) * get_kern_max_proc();
+       int i = 0, kp_cnt = 0;
+       
        if (!do_apple_internal_logging || j->anonymous || j->per_user) {
                return;
        }
 
        if (!do_apple_internal_logging || j->anonymous || j->per_user) {
                return;
        }
 
-       if (!job_assumes(j, (kp = malloc(len)) != NULL)) {
+       if (!job_assumes(j, (pids = malloc(len)) != NULL)) {
                return;
        }
                return;
        }
-       if (!job_assumes(j, sysctl(mib, (u_int) mib_sz, kp, &len, NULL, 0) != -1)) {
+       if (!job_assumes(j, (kp_cnt = proc_listchildpids(j->p, pids, len)) != -1)) {
                goto out;
        }
 
                goto out;
        }
 
-       kp_cnt = len / sizeof(struct kinfo_proc);
-
        for (i = 0; i < kp_cnt; i++) {
        for (i = 0; i < kp_cnt; i++) {
-#ifndef KERN_PROC_PPID
-               if (kp[i].kp_eproc.e_ppid != j->p) {
+               struct proc_bsdshortinfo proc;
+               if (proc_pidinfo(pids[i], PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
+                       if (errno != ESRCH) {
+                               job_assumes(j, errno == 0);
+                       }
                        continue;
                }
                        continue;
                }
-#endif
-               if (kp[i].kp_proc.p_flag & P_EXEC) {
+               if (proc.pbsi_flags & P_EXEC) {
                        continue;
                }
 
                        continue;
                }
 
-               job_log(j, LOG_DEBUG, "Called *fork(). Please switch to posix_spawn*(), pthreads or launchd. Child PID %u",
-                               kp[i].kp_proc.p_pid);
+               job_log(j, LOG_DEBUG, "Called *fork(). Please switch to posix_spawn*(), pthreads or launchd. Child PID %u", pids[i]);
        }
 
 out:
        }
 
 out:
-       free(kp);
+       free(pids);
 }
 
 void
 job_cleanup_after_tracer(job_t j)
 {
 }
 
 void
 job_cleanup_after_tracer(job_t j)
 {
-       jobmgr_t jm = NULL;
-       if( j->is_being_sampled ) {
-               int wstatus = 0;
-               job_log(j, LOG_DEBUG | LOG_CONSOLE, "sample[%i] finished with job.", j->tracing_pid);
-               if( job_assumes(j, waitpid(j->tracing_pid, &wstatus, 0) != -1) ) {
-                       job_assumes(j, WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0);
-               }
-               STAILQ_REMOVE(&j->mgr->pending_samples, j, job_s, pending_samples_sle);
-               
-               if( j->kill_after_sample ) {
-                       if (unlikely(j->debug_before_kill)) {
-                               job_log(j, LOG_NOTICE, "Exit timeout elapsed. Entering the kernel debugger");
-                               job_assumes(j, host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER) == KERN_SUCCESS);
-                       }
-                       
-                       job_log(j, LOG_NOTICE, "Killing...");
-                       job_kill(j);
-               }
-               j->sampling_complete = true;
-               j->is_being_sampled = false;
-               jm = j->mgr;
-       }
-
        j->tracing_pid = 0;
        j->tracing_pid = 0;
-       if( j->reap_after_trace ) {
+       if (j->reap_after_trace) {
                job_log(j, LOG_DEBUG | LOG_CONSOLE, "Reaping job now that attached tracer is gone.");
                struct kevent kev;
                EV_SET(&kev, j->p, 0, 0, NOTE_EXIT, 0, 0);
                job_log(j, LOG_DEBUG | LOG_CONSOLE, "Reaping job now that attached tracer is gone.");
                struct kevent kev;
                EV_SET(&kev, j->p, 0, 0, NOTE_EXIT, 0, 0);
-               
+
                /* Fake a kevent to keep our logic consistent. */
                job_callback_proc(j, &kev);
                /* Fake a kevent to keep our logic consistent. */
                job_callback_proc(j, &kev);
-               
+
                /* Normally, after getting a EVFILT_PROC event, we do garbage collection
                 * on the root job manager. To make our fakery complete, we will do garbage
                 * collection at the beginning of the next run loop cycle (after we're done
                 * draining the current queue of kevents).
                 */
                /* Normally, after getting a EVFILT_PROC event, we do garbage collection
                 * on the root job manager. To make our fakery complete, we will do garbage
                 * collection at the beginning of the next run loop cycle (after we're done
                 * draining the current queue of kevents).
                 */
-               job_assumes(j, kevent_mod((uintptr_t)&root_jobmgr->reboot_flags, EVFILT_TIMER, EV_ADD | EV_ONESHOT, NOTE_NSECONDS, 1, root_jobmgr) != -1);
-       }
-       
-       if( jm ) {
-               jobmgr_dequeue_next_sample(jm);
+               (void)job_assumes(j, kevent_mod((uintptr_t)&root_jobmgr->reboot_flags, EVFILT_TIMER, EV_ADD | EV_ONESHOT, NOTE_NSECONDS, 1, root_jobmgr) != -1);
        }
 }
 
        }
 }
 
@@ -3244,18 +3750,18 @@ job_callback_proc(job_t j, struct kevent *kev)
        bool program_changed = false;
        int fflags = kev->fflags;
        
        bool program_changed = false;
        int fflags = kev->fflags;
        
-       job_log(j, LOG_DEBUG, "EVFILT_PROC event for job:");
+       job_log(j, LOG_DEBUG, "EVFILT_PROC event for job.");
        log_kevent_struct(LOG_DEBUG, kev, 0);
        
        log_kevent_struct(LOG_DEBUG, kev, 0);
        
-       if( fflags & NOTE_EXIT ) {
-               if( j->p == (pid_t)kev->ident && !j->anonymous && !j->is_being_sampled ) {
-                       int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, j->p };
-                       struct kinfo_proc kp;
-                       size_t len = sizeof(kp);
-                       
-                       /* Sometimes, the kernel says it succeeded but really didn't. */
-                       if( job_assumes(j, sysctl(mib, 4, &kp, &len, NULL, 0) != -1) && len == sizeof(kp) ) {
-                               if( !job_assumes(j, kp.kp_eproc.e_ppid == getpid()) ) {
+       if (fflags & NOTE_EXIT) {
+               if (j->p == (pid_t)kev->ident && !j->anonymous) {
+                       /* Note that the third argument to proc_pidinfo() is a magic argument for
+                        * PROC_PIDT_SHORTBSDINFO. Specifically, passing 1 means "don't fail on a zombie
+                        * PID".
+                        */
+                       struct proc_bsdshortinfo proc;
+                       if (job_assumes(j, proc_pidinfo(j->p, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) > 0)) {
+                               if (!job_assumes(j, (pid_t)proc.pbsi_ppid == getpid())) {
                                        /* Someone has attached to the process with ptrace(). There's a race here. 
                                         * If we determine that we are not the parent process and then fail to attach 
                                         * a kevent to the parent PID (who is probably using ptrace()), we can take that as an
                                        /* Someone has attached to the process with ptrace(). There's a race here. 
                                         * If we determine that we are not the parent process and then fail to attach 
                                         * a kevent to the parent PID (who is probably using ptrace()), we can take that as an
@@ -3270,23 +3776,23 @@ job_callback_proc(job_t j, struct kevent *kev)
                                         * own parent. Apparently, that is not correct. If this is the case, we forsake
                                         * the process to its own devices. Let it reap itself.
                                         */
                                         * own parent. Apparently, that is not correct. If this is the case, we forsake
                                         * the process to its own devices. Let it reap itself.
                                         */
-                                       if( !job_assumes(j, kp.kp_eproc.e_ppid != (pid_t)kev->ident) ) {
+                                       if (!job_assumes(j, proc.pbsi_ppid != kev->ident)) {
                                                job_log(j, LOG_WARNING, "Job is its own parent and has (somehow) exited. Leaving it to waste away.");
                                                return;
                                        }
                                                job_log(j, LOG_WARNING, "Job is its own parent and has (somehow) exited. Leaving it to waste away.");
                                                return;
                                        }
-                                       if( job_assumes(j, kevent_mod(kp.kp_eproc.e_ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, j) != -1) ) {
-                                               j->tracing_pid = kp.kp_eproc.e_ppid;
+                                       if (job_assumes(j, kevent_mod(proc.pbsi_ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, j) != -1)) {
+                                               j->tracing_pid = proc.pbsi_ppid;
                                                j->reap_after_trace = true;
                                                return;
                                        }
                                }
                        }
                                                j->reap_after_trace = true;
                                                return;
                                        }
                                }
                        }
-               } else if( !j->anonymous ) {
-                       if( j->tracing_pid == (pid_t)kev->ident ) {
+               } else if (!j->anonymous) {
+                       if (j->tracing_pid == (pid_t)kev->ident) {
                                job_cleanup_after_tracer(j);
                                
                                return;
                                job_cleanup_after_tracer(j);
                                
                                return;
-                       } else if( j->tracing_pid && !j->reap_after_trace ) {
+                       } else if (j->tracing_pid && !j->reap_after_trace) {
                                /* The job exited before our sample completed. */
                                job_log(j, LOG_DEBUG | LOG_CONSOLE, "Job has exited. Will reap after tracing PID %i exits.", j->tracing_pid);
                                j->reap_after_trace = true;
                                /* The job exited before our sample completed. */
                                job_log(j, LOG_DEBUG | LOG_CONSOLE, "Job has exited. Will reap after tracing PID %i exits.", j->tracing_pid);
                                j->reap_after_trace = true;
@@ -3299,15 +3805,11 @@ job_callback_proc(job_t j, struct kevent *kev)
                program_changed = true;
 
                if (j->anonymous) {
                program_changed = true;
 
                if (j->anonymous) {
-                       int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, j->p };
-                       struct kinfo_proc kp;
-                       size_t len = sizeof(kp);
-
-                       /* Sometimes, the kernel says it succeeded but really didn't. */
-                       if (job_assumes(j, sysctl(mib, 4, &kp, &len, NULL, 0) != -1) && len == sizeof(kp)) {
+                       struct proc_bsdshortinfo proc;
+                       if (proc_pidinfo(j->p, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) > 0) {
                                char newlabel[1000];
 
                                char newlabel[1000];
 
-                               snprintf(newlabel, sizeof(newlabel), "%p.anonymous.%s", j, kp.kp_proc.p_comm);
+                               snprintf(newlabel, sizeof(newlabel), "%p.anonymous.%s", j, proc.pbsi_comm);
 
                                job_log(j, LOG_INFO, "Program changed. Updating the label to: %s", newlabel);
                                j->lastlookup = NULL;
 
                                job_log(j, LOG_INFO, "Program changed. Updating the label to: %s", newlabel);
                                j->lastlookup = NULL;
@@ -3315,13 +3817,37 @@ job_callback_proc(job_t j, struct kevent *kev)
 
                                LIST_REMOVE(j, label_hash_sle);
                                strcpy((char *)j->label, newlabel);
 
                                LIST_REMOVE(j, label_hash_sle);
                                strcpy((char *)j->label, newlabel);
-                               LIST_INSERT_HEAD(&label_hash[hash_label(j->label)], j, label_hash_sle);
+                               
+                               jobmgr_t where2put = root_jobmgr;
+                               if (j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN) {
+                                       where2put = j->mgr;
+                               }
+                               LIST_INSERT_HEAD(&where2put->label_hash[hash_label(j->label)], j, label_hash_sle);
+                       } else if (errno != ESRCH) {
+                               job_assumes(j, errno == 0);
                        }
                } else {
                        }
                } else {
-                       j->did_exec = true;
-                       job_log(j, LOG_DEBUG, "Program changed");
-               }
-       }
+                       if (j->spawn_reply_port) {
+                               errno = job_mig_spawn2_reply(j->spawn_reply_port, BOOTSTRAP_SUCCESS, j->p, j->exit_status_port);
+                               if (errno) {
+                                       if (errno != MACH_SEND_INVALID_DEST) {
+                                               (void)job_assumes(j, errno == KERN_SUCCESS);
+                                       }
+                                       (void)job_assumes(j, launchd_mport_close_recv(j->exit_status_port) == KERN_SUCCESS);
+                               }
+
+                               j->spawn_reply_port = MACH_PORT_NULL;
+                               j->exit_status_port = MACH_PORT_NULL;
+                       }
+
+                       if (j->xpc_service && j->did_exec) {
+                               j->xpcproxy_did_exec = true;
+                       }
+
+                       j->did_exec = true;
+                       job_log(j, LOG_DEBUG, "Program changed");
+               }
+       }
 
        if (fflags & NOTE_FORK) {
                job_log(j, LOG_DEBUG, "fork()ed%s", program_changed ? ". For this message only: We don't know whether this event happened before or after execve()." : "");
 
        if (fflags & NOTE_FORK) {
                job_log(j, LOG_DEBUG, "fork()ed%s", program_changed ? ". For this message only: We don't know whether this event happened before or after execve()." : "");
@@ -3331,11 +3857,11 @@ job_callback_proc(job_t j, struct kevent *kev)
        if (fflags & NOTE_EXIT) {
                job_reap(j);
 
        if (fflags & NOTE_EXIT) {
                job_reap(j);
 
-               if( !j->anonymous ) {
-                       j = job_dispatch(j, false);
-               } else {
+               if (j->anonymous) {
                        job_remove(j);
                        j = NULL;
                        job_remove(j);
                        j = NULL;
+               } else {
+                       j = job_dispatch(j, false);
                }
        }
 }
                }
        }
 }
@@ -3354,84 +3880,38 @@ job_callback_timer(job_t j, void *ident)
                j->start_pending = true;
                job_dispatch(j, false);
        } else if (&j->exit_timeout == ident) {
                j->start_pending = true;
                job_dispatch(j, false);
        } else if (&j->exit_timeout == ident) {
-               if( !job_assumes(j, j->p != 0) ) {
-                       return;
-               }
-               
-               if( j->clean_kill ) {
-                       job_log(j, LOG_ERR | LOG_CONSOLE, "Clean job failed to exit %u second after receiving SIGKILL.", LAUNCHD_CLEAN_KILL_TIMER);
-                       job_assumes(j, kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_DELETE, 0, 0, NULL));
-                       j->clean_exit_timer_expired = true;
-                       
-                       jobmgr_do_garbage_collection(j->mgr);
+               if (!job_assumes(j, j->p != 0)) {
                        return;
                }
                        return;
                }
-               
-               /*
-                * This block might be executed up to 3 times for a given (slow) job
-                *  - once for the SAMPLE_TIMEOUT timer, at which point sampling is triggered
-                *  - once for the exit_timeout timer, at which point:
-                *          - sampling is performed if not triggered previously
-                *          - SIGKILL is being sent to the job
-                *  - once for the SIGKILL_TIMER timer, at which point we log an issue
-                *    with the long SIGKILL
-                */
-               
-               if( j->per_user ) {
-                       /* Don't sample per-user launchd's. */
-                       j->sampling_complete = true;
-               }
-               bool was_is_or_will_be_sampled = ( j->sampling_complete || j->is_being_sampled || j->pending_sample );
-               bool should_enqueue = ( !was_is_or_will_be_sampled && do_apple_internal_logging );
-               
+
                if (j->sent_sigkill) {
                        uint64_t td = runtime_get_nanoseconds_since(j->sent_signal_time);
 
                        td /= NSEC_PER_SEC;
                        td -= j->clean_kill ? 0 : j->exit_timeout;
 
                if (j->sent_sigkill) {
                        uint64_t td = runtime_get_nanoseconds_since(j->sent_signal_time);
 
                        td /= NSEC_PER_SEC;
                        td -= j->clean_kill ? 0 : j->exit_timeout;
 
-                       job_log(j, LOG_WARNING | LOG_CONSOLE, "Did not die after sending SIGKILL %llu seconds ago...", td);
-               } else if( should_enqueue && (!j->exit_timeout || (LAUNCHD_SAMPLE_TIMEOUT < j->exit_timeout)) ) {
-                       /* This should work even if the job changes its exit_timeout midstream */
-                       job_log(j, LOG_NOTICE | LOG_CONSOLE, "Sampling timeout elapsed (%u seconds). Scheduling a sample...", LAUNCHD_SAMPLE_TIMEOUT);
-                       if (j->exit_timeout) {
-                               unsigned int ttk = (j->exit_timeout - LAUNCHD_SAMPLE_TIMEOUT);
-                               job_assumes(j, kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER,
-                                                                                 EV_ADD|EV_ONESHOT, NOTE_SECONDS, ttk, j) != -1);
-                               job_log(j, LOG_NOTICE | LOG_CONSOLE, "Scheduled new exit timeout for %u seconds later", ttk);
+                       job_log(j, LOG_WARNING | LOG_CONSOLE, "Job has not died after being %skilled %llu seconds ago. Simulating exit.", j->clean_kill ? "cleanly " : "", td);
+                       j->workaround9359725 = true;
+
+                       if (g_trap_sigkill_bugs) {
+                               job_log(j, LOG_NOTICE | LOG_CONSOLE, "Trapping into kernel debugger. You can continue the machine after it has been debugged, and shutdown will proceed normally.");
+                               (void)job_assumes(j, host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER) == KERN_SUCCESS);
                        }
                        }
-                       
-                       STAILQ_INSERT_TAIL(&j->mgr->pending_samples, j, pending_samples_sle);
-                       j->pending_sample = true;
-                       jobmgr_dequeue_next_sample(j->mgr);
-               } else {
-                       if( do_apple_internal_logging && !j->sampling_complete ) {
-                               if( j->is_being_sampled || j->pending_sample ) {
-                                       char pidstr[24] = { 0 };
-                                       snprintf(pidstr, sizeof(pidstr), "[%i] ", j->tracing_pid);
-                                       
-                                       job_log(j, LOG_DEBUG | LOG_CONSOLE, "Exit timeout elapsed (%u seconds). Will kill after sample%shas completed.", j->exit_timeout, j->tracing_pid ? pidstr : " ");
-                                       j->kill_after_sample = true;
-                               } else {
-                                       job_log(j, LOG_DEBUG | LOG_CONSOLE, "Exit timeout elapsed (%u seconds). Will sample and then kill.", j->exit_timeout);
-                                       
-                                       STAILQ_INSERT_TAIL(&j->mgr->pending_samples, j, pending_samples_sle);
-                                       j->pending_sample = true;
-                               }                       
 
 
-                               jobmgr_dequeue_next_sample(j->mgr);
-                       } else {
-                               if (unlikely(j->debug_before_kill)) {
-                                       job_log(j, LOG_NOTICE, "Exit timeout elapsed. Entering the kernel debugger");
-                                       job_assumes(j, host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER) == KERN_SUCCESS);
-                               }
-                               job_log(j, LOG_WARNING | LOG_CONSOLE, "Exit timeout elapsed (%u seconds). Killing", j->exit_timeout);
-                               job_kill(j);
-                               jobmgr_do_garbage_collection(j->mgr);
+                       struct kevent bogus_exit;
+                       EV_SET(&bogus_exit, j->p, EVFILT_PROC, 0, NOTE_EXIT, 0, 0);
+                       jobmgr_callback(j->mgr, &bogus_exit);
+               } else {
+                       if (unlikely(j->debug_before_kill)) {
+                               job_log(j, LOG_NOTICE, "Exit timeout elapsed. Entering the kernel debugger");
+                               (void)job_assumes(j, host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER) == KERN_SUCCESS);
                        }
                        }
+
+                       job_log(j, LOG_WARNING | LOG_CONSOLE, "Exit timeout elapsed (%u seconds). Killing", j->exit_timeout);
+                       job_kill(j);
                }
        } else {
                }
        } else {
-               job_assumes(j, false);
+               (void)job_assumes(j, false);
        }
 }
 
        }
 }
 
@@ -3494,7 +3974,7 @@ jobmgr_callback(void *obj, struct kevent *kev)
 
                                LIST_FOREACH(ji, &root_jobmgr->jobs, sle) {
                                        if (ji->per_user && ji->p) {
 
                                LIST_FOREACH(ji, &root_jobmgr->jobs, sle) {
                                        if (ji->per_user && ji->p) {
-                                               job_assumes(ji, runtime_kill(ji->p, SIGUSR2) != -1);
+                                               (void)job_assumes(ji, runtime_kill(ji->p, SIGUSR2) != -1);
                                        }
                                }
                        } else {
                                        }
                                }
                        } else {
@@ -3513,34 +3993,34 @@ jobmgr_callback(void *obj, struct kevent *kev)
                jobmgr_dispatch_all_semaphores(jm);
                break;
        case EVFILT_TIMER:
                jobmgr_dispatch_all_semaphores(jm);
                break;
        case EVFILT_TIMER:
-               if( kev->ident == (uintptr_t)&sorted_calendar_events ) {
+               if (kev->ident == (uintptr_t)&sorted_calendar_events) {
                        calendarinterval_callback();
                        calendarinterval_callback();
-               } else if( kev->ident == (uintptr_t)jm ) {
+               } else if (kev->ident == (uintptr_t)jm) {
                        jobmgr_log(jm, LOG_DEBUG, "Shutdown timer firing.");
                        jobmgr_still_alive_with_check(jm);
                        jobmgr_log(jm, LOG_DEBUG, "Shutdown timer firing.");
                        jobmgr_still_alive_with_check(jm);
-               } else if( kev->ident == (uintptr_t)&jm->reboot_flags ) {
+               } else if (kev->ident == (uintptr_t)&jm->reboot_flags) {
                        jobmgr_do_garbage_collection(jm);
                        jobmgr_do_garbage_collection(jm);
-               } else if( kev->ident == (uintptr_t)&g_runtime_busy_time ) {
+               } else if (kev->ident == (uintptr_t)&g_runtime_busy_time) {
                        jobmgr_log(jm, LOG_DEBUG, "Idle exit timer fired. Shutting down.");
                        jobmgr_log(jm, LOG_DEBUG, "Idle exit timer fired. Shutting down.");
-                       if( jobmgr_assumes(jm, runtime_busy_cnt == 0) ) {
+                       if (jobmgr_assumes(jm, runtime_busy_cnt == 0)) {
                                return launchd_shutdown();
                        }
                }
                break;
        case EVFILT_VNODE:
                                return launchd_shutdown();
                        }
                }
                break;
        case EVFILT_VNODE:
-               if( kev->ident == (uintptr_t)s_no_hang_fd ) {
+               if (kev->ident == (uintptr_t)s_no_hang_fd) {
                        int _no_hang_fd = open("/dev/autofs_nowait", O_EVTONLY | O_NONBLOCK);
                        int _no_hang_fd = open("/dev/autofs_nowait", O_EVTONLY | O_NONBLOCK);
-                       if( unlikely(_no_hang_fd != -1) ) {
+                       if (unlikely(_no_hang_fd != -1)) {
                                jobmgr_log(root_jobmgr, LOG_DEBUG, "/dev/autofs_nowait has appeared!");
                                jobmgr_log(root_jobmgr, LOG_DEBUG, "/dev/autofs_nowait has appeared!");
-                               jobmgr_assumes(root_jobmgr, kevent_mod((uintptr_t)s_no_hang_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL) != -1);
-                               jobmgr_assumes(root_jobmgr, runtime_close(s_no_hang_fd) != -1);
+                               (void)jobmgr_assumes(root_jobmgr, kevent_mod((uintptr_t)s_no_hang_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL) != -1);
+                               (void)jobmgr_assumes(root_jobmgr, runtime_close(s_no_hang_fd) != -1);
                                s_no_hang_fd = _fd(_no_hang_fd);
                        }
                                s_no_hang_fd = _fd(_no_hang_fd);
                        }
-               } else if( pid1_magic && g_console && kev->ident == (uintptr_t)fileno(g_console) ) {
+               } else if (pid1_magic && g_console && kev->ident == (uintptr_t)fileno(g_console)) {
                        int cfd = -1;
                        int cfd = -1;
-                       if( launchd_assumes((cfd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) != -1) ) {
+                       if (launchd_assumes((cfd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) != -1)) {
                                _fd(cfd);
                                _fd(cfd);
-                               if( !launchd_assumes((g_console = fdopen(cfd, "w")) != NULL) ) {
+                               if (!launchd_assumes((g_console = fdopen(cfd, "w")) != NULL)) {
                                        close(cfd);
                                }
                        }
                                        close(cfd);
                                }
                        }
@@ -3605,14 +4085,18 @@ job_start(job_t j)
        
        if (j->start_time && (td < j->min_run_time) && !j->legacy_mach_job && !j->inetcompat) {
                time_t respawn_delta = j->min_run_time - (uint32_t)td;
        
        if (j->start_time && (td < j->min_run_time) && !j->legacy_mach_job && !j->inetcompat) {
                time_t respawn_delta = j->min_run_time - (uint32_t)td;
-               
+
                /*
                 * We technically should ref-count throttled jobs to prevent idle exit,
                 * but we're not directly tracking the 'throttled' state at the moment.
                 */
                /*
                 * We technically should ref-count throttled jobs to prevent idle exit,
                 * but we're not directly tracking the 'throttled' state at the moment.
                 */
-               
-               job_log(j, LOG_WARNING, "Throttling respawn: Will start in %ld seconds", respawn_delta);
-               job_assumes(j, kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, respawn_delta, j) != -1);
+               int level = LOG_WARNING;
+               if (!j->did_exec && ((j->fail_cnt - 1) % LAUNCHD_LOG_FAILED_EXEC_FREQ) != 0) {
+                       level = LOG_DEBUG;
+               }
+
+               job_log(j, level, "Throttling respawn: Will start in %ld seconds", respawn_delta);
+               (void)job_assumes(j, kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, respawn_delta, j) != -1);
                job_ignore(j);
                return;
        }
                job_ignore(j);
                return;
        }
@@ -3621,33 +4105,33 @@ job_start(job_t j)
                sipc = ((!SLIST_EMPTY(&j->sockets) || !SLIST_EMPTY(&j->machservices)) && !j->deny_job_creation) || j->embedded_special_privileges;
        }
 
                sipc = ((!SLIST_EMPTY(&j->sockets) || !SLIST_EMPTY(&j->machservices)) && !j->deny_job_creation) || j->embedded_special_privileges;
        }
 
-       if( sipc ) {
-               job_assumes(j, socketpair(AF_UNIX, SOCK_STREAM, 0, spair) != -1);
+       if (sipc) {
+               (void)job_assumes(j, socketpair(AF_UNIX, SOCK_STREAM, 0, spair) != -1);
        }
        
        }
        
-       job_assumes(j, socketpair(AF_UNIX, SOCK_STREAM, 0, execspair) != -1);
+       (void)job_assumes(j, socketpair(AF_UNIX, SOCK_STREAM, 0, execspair) != -1);
        
        if (likely(!j->legacy_mach_job) && job_assumes(j, pipe(oepair) != -1)) {
                j->log_redirect_fd = _fd(oepair[0]);
        
        if (likely(!j->legacy_mach_job) && job_assumes(j, pipe(oepair) != -1)) {
                j->log_redirect_fd = _fd(oepair[0]);
-               job_assumes(j, fcntl(j->log_redirect_fd, F_SETFL, O_NONBLOCK) != -1);
-               job_assumes(j, kevent_mod(j->log_redirect_fd, EVFILT_READ, EV_ADD, 0, 0, j) != -1);
+               (void)job_assumes(j, fcntl(j->log_redirect_fd, F_SETFL, O_NONBLOCK) != -1);
+               (void)job_assumes(j, kevent_mod(j->log_redirect_fd, EVFILT_READ, EV_ADD, 0, 0, j) != -1);
        }
        
        switch (c = runtime_fork(j->weird_bootstrap ? j->j_port : j->mgr->jm_port)) {
        case -1:
                job_log_error(j, LOG_ERR, "fork() failed, will try again in one second");
        }
        
        switch (c = runtime_fork(j->weird_bootstrap ? j->j_port : j->mgr->jm_port)) {
        case -1:
                job_log_error(j, LOG_ERR, "fork() failed, will try again in one second");
-               job_assumes(j, kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, 1, j) != -1);
+               (void)job_assumes(j, kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, 1, j) != -1);
                job_ignore(j);
                
                job_ignore(j);
                
-               job_assumes(j, runtime_close(execspair[0]) == 0);
-               job_assumes(j, runtime_close(execspair[1]) == 0);
+               (void)job_assumes(j, runtime_close(execspair[0]) == 0);
+               (void)job_assumes(j, runtime_close(execspair[1]) == 0);
                if (sipc) {
                if (sipc) {
-                       job_assumes(j, runtime_close(spair[0]) == 0);
-                       job_assumes(j, runtime_close(spair[1]) == 0);
+                       (void)job_assumes(j, runtime_close(spair[0]) == 0);
+                       (void)job_assumes(j, runtime_close(spair[1]) == 0);
                }
                if (likely(!j->legacy_mach_job)) {
                }
                if (likely(!j->legacy_mach_job)) {
-                       job_assumes(j, runtime_close(oepair[0]) != -1);
-                       job_assumes(j, runtime_close(oepair[1]) != -1);
+                       (void)job_assumes(j, runtime_close(oepair[0]) != -1);
+                       (void)job_assumes(j, runtime_close(oepair[1]) != -1);
                        j->log_redirect_fd = 0;
                }
                break;
                        j->log_redirect_fd = 0;
                }
                break;
@@ -3656,16 +4140,16 @@ job_start(job_t j)
                        _exit(EXIT_FAILURE);
                }
                if (!j->legacy_mach_job) {
                        _exit(EXIT_FAILURE);
                }
                if (!j->legacy_mach_job) {
-                       job_assumes(j, dup2(oepair[1], STDOUT_FILENO) != -1);
-                       job_assumes(j, dup2(oepair[1], STDERR_FILENO) != -1);
-                       job_assumes(j, runtime_close(oepair[1]) != -1);
+                       (void)job_assumes(j, dup2(oepair[1], STDOUT_FILENO) != -1);
+                       (void)job_assumes(j, dup2(oepair[1], STDERR_FILENO) != -1);
+                       (void)job_assumes(j, runtime_close(oepair[1]) != -1);
                }
                }
-               job_assumes(j, runtime_close(execspair[0]) == 0);
+               (void)job_assumes(j, runtime_close(execspair[0]) == 0);
                /* wait for our parent to say they've attached a kevent to us */
                read(_fd(execspair[1]), &c, sizeof(c));
                
                if (sipc) {
                /* wait for our parent to say they've attached a kevent to us */
                read(_fd(execspair[1]), &c, sizeof(c));
                
                if (sipc) {
-                       job_assumes(j, runtime_close(spair[0]) == 0);
+                       (void)job_assumes(j, runtime_close(spair[0]) == 0);
                        snprintf(nbuf, sizeof(nbuf), "%d", spair[1]);
                        setenv(LAUNCHD_TRUSTED_FD_ENV, nbuf, 1);
                }
                        snprintf(nbuf, sizeof(nbuf), "%d", spair[1]);
                        setenv(LAUNCHD_TRUSTED_FD_ENV, nbuf, 1);
                }
@@ -3677,20 +4161,21 @@ job_start(job_t j)
                job_log(j, LOG_DEBUG, "Started as PID: %u", c);
                
                j->did_exec = false;
                job_log(j, LOG_DEBUG, "Started as PID: %u", c);
                
                j->did_exec = false;
+               j->xpcproxy_did_exec = false;
                j->checkedin = false;
                j->start_pending = false;
                j->reaped = false;
                j->crashed = false;
                j->stopped = false;
                j->checkedin = false;
                j->start_pending = false;
                j->reaped = false;
                j->crashed = false;
                j->stopped = false;
-               if( j->needs_kickoff ) {
+               if (j->needs_kickoff) {
                        j->needs_kickoff = false;
                        
                        j->needs_kickoff = false;
                        
-                       if( SLIST_EMPTY(&j->semaphores) ) {
+                       if (SLIST_EMPTY(&j->semaphores)) {
                                j->ondemand = false;
                        }
                }
                
                                j->ondemand = false;
                        }
                }
                
-               if( j->has_console ) {
+               if (j->has_console) {
                        g_wsp = c;
                }
                
                        g_wsp = c;
                }
                
@@ -3699,18 +4184,15 @@ job_start(job_t j)
                LIST_INSERT_HEAD(&j->mgr->active_jobs[ACTIVE_JOB_HASH(c)], j, pid_hash_sle);
                
                if (likely(!j->legacy_mach_job)) {
                LIST_INSERT_HEAD(&j->mgr->active_jobs[ACTIVE_JOB_HASH(c)], j, pid_hash_sle);
                
                if (likely(!j->legacy_mach_job)) {
-                       job_assumes(j, runtime_close(oepair[1]) != -1);
+                       (void)job_assumes(j, runtime_close(oepair[1]) != -1);
                }
                j->p = c;
                }
                j->p = c;
-               if (unlikely(j->hopefully_exits_first)) {
-                       j->mgr->hopefully_first_cnt++;
-               } else if (likely(!j->hopefully_exits_last)) {
-                       j->mgr->normal_active_cnt++;
-               }
+
+               j->mgr->normal_active_cnt++;
                j->fork_fd = _fd(execspair[0]);
                j->fork_fd = _fd(execspair[0]);
-               job_assumes(j, runtime_close(execspair[1]) == 0);
+               (void)job_assumes(j, runtime_close(execspair[1]) == 0);
                if (sipc) {
                if (sipc) {
-                       job_assumes(j, runtime_close(spair[1]) == 0);
+                       (void)job_assumes(j, runtime_close(spair[1]) == 0);
                        ipc_open(_fd(spair[0]), j);
                }
                if (job_assumes(j, kevent_mod(c, EVFILT_PROC, EV_ADD, proc_fflags, 0, root_jobmgr ? root_jobmgr : j->mgr) != -1)) {
                        ipc_open(_fd(spair[0]), j);
                }
                if (job_assumes(j, kevent_mod(c, EVFILT_PROC, EV_ADD, proc_fflags, 0, root_jobmgr ? root_jobmgr : j->mgr) != -1)) {
@@ -3722,8 +4204,8 @@ job_start(job_t j)
                j->wait4debugger_oneshot = false;
 
                struct envitem *ei = NULL, *et = NULL;
                j->wait4debugger_oneshot = false;
 
                struct envitem *ei = NULL, *et = NULL;
-               SLIST_FOREACH_SAFE( ei, &j->env, sle, et ) {
-                       if( ei->one_shot ) {
+               SLIST_FOREACH_SAFE(ei, &j->env, sle, et) {
+                       if (ei->one_shot) {
                                SLIST_REMOVE(&j->env, ei, envitem, sle);
                        }
                }
                                SLIST_REMOVE(&j->env, ei, envitem, sle);
                        }
                }
@@ -3748,7 +4230,7 @@ job_start_child(job_t j)
        size_t binpref_out_cnt = 0;
        size_t i;
 
        size_t binpref_out_cnt = 0;
        size_t i;
 
-       job_assumes(j, posix_spawnattr_init(&spattr) == 0);
+       (void)job_assumes(j, posix_spawnattr_init(&spattr) == 0);
 
        job_setup_attributes(j);
 
 
        job_setup_attributes(j);
 
@@ -3784,15 +4266,22 @@ job_start_child(job_t j)
        }
 
        if (unlikely(j->wait4debugger || j->wait4debugger_oneshot)) {
        }
 
        if (unlikely(j->wait4debugger || j->wait4debugger_oneshot)) {
-               job_log(j, LOG_WARNING, "Spawned and waiting for the debugger to attach before continuing...");
+               if (!j->legacy_LS_job) {
+                       job_log(j, LOG_WARNING, "Spawned and waiting for the debugger to attach before continuing...");
+               }
                spflags |= POSIX_SPAWN_START_SUSPENDED;
        }
 
                spflags |= POSIX_SPAWN_START_SUSPENDED;
        }
 
-       job_assumes(j, posix_spawnattr_setflags(&spattr, spflags) == 0);
+       if (unlikely(j->disable_aslr)) {
+               spflags |= _POSIX_SPAWN_DISABLE_ASLR;
+       }
+       spflags |= j->pstype;
+
+       (void)job_assumes(j, posix_spawnattr_setflags(&spattr, spflags) == 0);
 
        if (unlikely(j->j_binpref_cnt)) {
 
        if (unlikely(j->j_binpref_cnt)) {
-               job_assumes(j, posix_spawnattr_setbinpref_np(&spattr, j->j_binpref_cnt, j->j_binpref, &binpref_out_cnt) == 0);
-               job_assumes(j, binpref_out_cnt == j->j_binpref_cnt);
+               (void)job_assumes(j, posix_spawnattr_setbinpref_np(&spattr, j->j_binpref_cnt, j->j_binpref, &binpref_out_cnt) == 0);
+               (void)job_assumes(j, binpref_out_cnt == j->j_binpref_cnt);
        }
 
 #if HAVE_QUARANTINE
        }
 
 #if HAVE_QUARANTINE
@@ -3801,7 +4290,7 @@ job_start_child(job_t j)
 
                if (job_assumes(j, qp = qtn_proc_alloc())) {
                        if (job_assumes(j, qtn_proc_init_with_data(qp, j->quarantine_data, j->quarantine_data_sz) == 0)) {
 
                if (job_assumes(j, qp = qtn_proc_alloc())) {
                        if (job_assumes(j, qtn_proc_init_with_data(qp, j->quarantine_data, j->quarantine_data_sz) == 0)) {
-                               job_assumes(j, qtn_proc_apply_to_self(qp) == 0);
+                               (void)job_assumes(j, qtn_proc_apply_to_self(qp) == 0);
                        }
                }
        }
                        }
                }
        }
@@ -3826,13 +4315,20 @@ job_start_child(job_t j)
                file2exec = j->prog ? j->prog : argv[0];
        }
 
                file2exec = j->prog ? j->prog : argv[0];
        }
 
-       errno = psf(NULL, file2exec, NULL, &spattr, (char *const*)argv, environ);
-       job_log_error(j, LOG_ERR, "posix_spawn(\"%s\", ...)", file2exec);
-       
+       errno = psf(NULL, file2exec, NULL, &spattr, (char *const *)argv, environ);
+       if (errno != EBADARCH) {
+               int level = LOG_ERR;
+               if ((j->fail_cnt++ % LAUNCHD_LOG_FAILED_EXEC_FREQ) != 0) {
+                       level = LOG_DEBUG;
+               }
+               job_log_error(j, level, "posix_spawn(\"%s\", ...)", file2exec);
+               errno = EXIT_FAILURE;
+       }
+
 #if HAVE_SANDBOX
 out_bad:
 #endif
 #if HAVE_SANDBOX
 out_bad:
 #endif
-       _exit(EXIT_FAILURE);
+       _exit(errno);
 }
 
 void
 }
 
 void
@@ -3885,51 +4381,71 @@ jobmgr_setup_env_from_other_jobs(jobmgr_t jm)
 void
 job_log_pids_with_weird_uids(job_t j)
 {
 void
 job_log_pids_with_weird_uids(job_t j)
 {
-       int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
-       size_t i, kp_cnt, len = sizeof(struct kinfo_proc) * get_kern_max_proc();
-       struct kinfo_proc *kp;
+       size_t len = sizeof(pid_t) * get_kern_max_proc();
+       pid_t *pids = NULL;
        uid_t u = j->mach_uid;
        uid_t u = j->mach_uid;
-
+       int i = 0, kp_cnt = 0;
+       
        if (!do_apple_internal_logging) {
                return;
        }
 
        if (!do_apple_internal_logging) {
                return;
        }
 
-       kp = malloc(len);
-
-       if (!job_assumes(j, kp != NULL)) {
+       pids = malloc(len);
+       if (!job_assumes(j, pids != NULL)) {
                return;
        }
 
        runtime_ktrace(RTKT_LAUNCHD_FINDING_WEIRD_UIDS, j->p, u, 0);
 
                return;
        }
 
        runtime_ktrace(RTKT_LAUNCHD_FINDING_WEIRD_UIDS, j->p, u, 0);
 
-       if (!job_assumes(j, sysctl(mib, 3, kp, &len, NULL, 0) != -1)) {
+       /* libproc actually has some serious performance drawbacks when used over sysctl(3) in
+        * scenarios like this. Whereas sysctl(3) can give us back all the kinfo_proc's in
+        * one kernel call, libproc requires that we get a list of PIDs we're interested in
+        * (in this case, all PIDs on the system) and then get a single proc_bsdshortinfo
+        * struct back in a single call for each one.
+        *
+        * This kind of thing is also more inherently racy than sysctl(3). While sysctl(3)
+        * returns a snapshot, it returns the whole shebang at once. Any PIDs given to us by
+        * libproc could go stale before we call proc_pidinfo().
+        *
+        * Note that proc_list*() APIs return the number of PIDs given back, not the number
+        * of bytes written to the buffer.
+        */
+       if (!job_assumes(j, (kp_cnt = proc_listallpids(pids, len)) != -1)) {
                goto out;
        }
 
                goto out;
        }
 
-       kp_cnt = len / sizeof(struct kinfo_proc);
-
        for (i = 0; i < kp_cnt; i++) {
        for (i = 0; i < kp_cnt; i++) {
-               uid_t i_euid = kp[i].kp_eproc.e_ucred.cr_uid;
-               uid_t i_uid = kp[i].kp_eproc.e_pcred.p_ruid;
-               uid_t i_svuid = kp[i].kp_eproc.e_pcred.p_svuid;
-               pid_t i_pid = kp[i].kp_proc.p_pid;
+               struct proc_bsdshortinfo proc;
+               /* We perhaps should not log a bug here if we get ESRCH back, due to the race
+                * detailed above.
+                */
+               if (proc_pidinfo(pids[i], PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
+                       if (errno != ESRCH) {
+                               job_assumes(j, errno == 0);
+                       }
+                       continue;
+               }
+               
+               uid_t i_euid = proc.pbsi_uid;
+               uid_t i_uid = proc.pbsi_ruid;
+               uid_t i_svuid = proc.pbsi_svuid;
+               pid_t i_pid = pids[i];
 
                if (i_euid != u && i_uid != u && i_svuid != u) {
                        continue;
                }
 
 
                if (i_euid != u && i_uid != u && i_svuid != u) {
                        continue;
                }
 
-               job_log(j, LOG_ERR, "PID %u \"%s\" has no account to back it! Real/effective/saved UIDs: %u/%u/%u",
-                               i_pid, kp[i].kp_proc.p_comm, i_uid, i_euid, i_svuid);
+               job_log(j, LOG_ERR, "PID %u \"%s\" has no account to back it! Real/effective/saved UIDs: %u/%u/%u", i_pid, proc.pbsi_comm, i_uid, i_euid, i_svuid);
 
 /* Temporarily disabled due to 5423935 and 4946119. */
 #if 0
                /* Ask the accountless process to exit. */
 
 /* Temporarily disabled due to 5423935 and 4946119. */
 #if 0
                /* Ask the accountless process to exit. */
-               job_assumes(j, runtime_kill(i_pid, SIGTERM) != -1);
+               (void)job_assumes(j, runtime_kill(i_pid, SIGTERM) != -1);
 #endif
        }
 
 out:
 #endif
        }
 
 out:
-       free(kp);
+       free(pids);
 }
 
 void
 }
 
 void
@@ -3995,7 +4511,7 @@ job_postfork_test_user(job_t j)
        return;
 out_bad:
 #if 0
        return;
 out_bad:
 #if 0
-       job_assumes(j, runtime_kill(getppid(), SIGTERM) != -1);
+       (void)job_assumes(j, runtime_kill(getppid(), SIGTERM) != -1);
        _exit(EXIT_FAILURE);
 #else
        job_log(j, LOG_WARNING, "In a future build of the OS, this error will be fatal.");
        _exit(EXIT_FAILURE);
 #else
        job_log(j, LOG_WARNING, "In a future build of the OS, this error will be fatal.");
@@ -4105,9 +4621,9 @@ job_postfork_become_user(job_t j)
                int groups[NGROUPS], ngroups;
                
                /* A failure here isn't fatal, and we'll still get data we can use. */
                int groups[NGROUPS], ngroups;
                
                /* A failure here isn't fatal, and we'll still get data we can use. */
-               job_assumes(j, getgrouplist(j->username, desired_gid, groups, &ngroups) != -1);
+               (void)job_assumes(j, getgrouplist(j->username, desired_gid, groups, &ngroups) != -1);
                
                
-               if( !job_assumes(j, syscall(SYS_initgroups, ngroups, groups, desired_uid) != -1) ) {
+               if (!job_assumes(j, syscall(SYS_initgroups, ngroups, groups, desired_uid) != -1)) {
                        _exit(EXIT_FAILURE);
                }
        #endif
                        _exit(EXIT_FAILURE);
                }
        #endif
@@ -4136,7 +4652,7 @@ job_setup_attributes(job_t j)
        struct envitem *ei;
 
        if (unlikely(j->setnice)) {
        struct envitem *ei;
 
        if (unlikely(j->setnice)) {
-               job_assumes(j, setpriority(PRIO_PROCESS, 0, j->nice) != -1);
+               (void)job_assumes(j, setpriority(PRIO_PROCESS, 0, j->nice) != -1);
        }
 
        SLIST_FOREACH(li, &j->limits, sle) {
        }
 
        SLIST_FOREACH(li, &j->limits, sle) {
@@ -4158,40 +4674,22 @@ job_setup_attributes(job_t j)
                }
        }
 
                }
        }
 
-#if !TARGET_OS_EMBEDDED
-       if( unlikely(j->per_user) ) {
-               auditinfo_addr_t auinfo = {
-                       .ai_termid = { .at_type = AU_IPv4 },
-                       .ai_auid = j->mach_uid,
-                       .ai_asid = AU_ASSIGN_ASID,
-               };
-               (void)au_user_mask(j->username, &auinfo.ai_mask);
-               
-               if( !launchd_assumes(setaudit_addr(&auinfo, sizeof(auinfo)) != -1) ) {
-                       runtime_syslog(LOG_WARNING, "Could not set audit session! (errno = %d)", errno);
-                       _exit(EXIT_FAILURE);
-               } else {
-                       job_log(j, LOG_DEBUG, "Created new security session for per-user launchd.");
-               }
-       }
-#endif
-
        if (unlikely(!j->inetcompat && j->session_create)) {
                launchd_SessionCreate();
        }
 
        if (unlikely(j->low_pri_io)) {
        if (unlikely(!j->inetcompat && j->session_create)) {
                launchd_SessionCreate();
        }
 
        if (unlikely(j->low_pri_io)) {
-               job_assumes(j, setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE) != -1);
+               (void)job_assumes(j, setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE) != -1);
        }
        if (unlikely(j->rootdir)) {
        }
        if (unlikely(j->rootdir)) {
-               job_assumes(j, chroot(j->rootdir) != -1);
-               job_assumes(j, chdir(".") != -1);
+               (void)job_assumes(j, chroot(j->rootdir) != -1);
+               (void)job_assumes(j, chdir(".") != -1);
        }
 
        job_postfork_become_user(j);
 
        if (unlikely(j->workingdir)) {
        }
 
        job_postfork_become_user(j);
 
        if (unlikely(j->workingdir)) {
-               job_assumes(j, chdir(j->workingdir) != -1);
+               (void)job_assumes(j, chdir(j->workingdir) != -1);
        }
 
        if (unlikely(j->setmask)) {
        }
 
        if (unlikely(j->setmask)) {
@@ -4199,7 +4697,7 @@ job_setup_attributes(job_t j)
        }
 
        if (j->stdin_fd) {
        }
 
        if (j->stdin_fd) {
-               job_assumes(j, dup2(j->stdin_fd, STDIN_FILENO) != -1);
+               (void)job_assumes(j, dup2(j->stdin_fd, STDIN_FILENO) != -1);
        } else {
                job_setup_fd(j, STDIN_FILENO, j->stdinpath, O_RDONLY|O_CREAT);
        }
        } else {
                job_setup_fd(j, STDIN_FILENO, j->stdinpath, O_RDONLY|O_CREAT);
        }
@@ -4212,22 +4710,22 @@ job_setup_attributes(job_t j)
                setenv(ei->key, ei->value, 1);
        }
 
                setenv(ei->key, ei->value, 1);
        }
 
-       if( do_apple_internal_logging ) {
+       if (do_apple_internal_logging) {
                setenv(LAUNCHD_DO_APPLE_INTERNAL_LOGGING, "true", 1);
        }
 
 #if !TARGET_OS_EMBEDDED        
                setenv(LAUNCHD_DO_APPLE_INTERNAL_LOGGING, "true", 1);
        }
 
 #if !TARGET_OS_EMBEDDED        
-       if( j->jetsam_properties ) {
-               job_assumes(j, proc_setpcontrol(PROC_SETPC_TERMINATE) == 0);
+       if (j->jetsam_properties) {
+               (void)job_assumes(j, proc_setpcontrol(PROC_SETPC_TERMINATE) == 0);
        }
 #endif
 
 #if TARGET_OS_EMBEDDED
        }
 #endif
 
 #if TARGET_OS_EMBEDDED
-       if( j->main_thread_priority != 0 ) {
+       if (j->main_thread_priority != 0) {
                struct sched_param params;
                bzero(&params, sizeof(params));
                params.sched_priority = j->main_thread_priority;
                struct sched_param params;
                bzero(&params, sizeof(params));
                params.sched_priority = j->main_thread_priority;
-               job_assumes(j, pthread_setschedparam(pthread_self(), SCHED_OTHER, &params) != -1);
+               (void)job_assumes(j, pthread_setschedparam(pthread_self(), SCHED_OTHER, &params) != -1);
        }
 #endif
 
        }
 #endif
 
@@ -4237,9 +4735,9 @@ job_setup_attributes(job_t j)
         * setuid children. We'll settle for process-groups.
         */
        if (getppid() != 1) {
         * setuid children. We'll settle for process-groups.
         */
        if (getppid() != 1) {
-               job_assumes(j, setpgid(0, 0) != -1);
+               (void)job_assumes(j, setpgid(0, 0) != -1);
        } else {
        } else {
-               job_assumes(j, setsid() != -1);
+               (void)job_assumes(j, setsid() != -1);
        }
 }
 
        }
 }
 
@@ -4257,8 +4755,8 @@ job_setup_fd(job_t j, int target_fd, const char *path, int flags)
                return;
        }
 
                return;
        }
 
-       job_assumes(j, dup2(fd, target_fd) != -1);
-       job_assumes(j, runtime_close(fd) == 0);
+       (void)job_assumes(j, dup2(fd, target_fd) != -1);
+       (void)job_assumes(j, runtime_close(fd) == 0);
 }
 
 int
 }
 
 int
@@ -4279,7 +4777,7 @@ dir_has_files(job_t j, const char *path)
                }
        }
 
                }
        }
 
-       job_assumes(j, closedir(dd) == 0);
+       (void)job_assumes(j, closedir(dd) == 0);
        return r;
 }
 
        return r;
 }
 
@@ -4403,7 +4901,6 @@ job_log_bug(job_t j, unsigned int line)
                }
        }
 
                }
        }
 
-       /* I cannot think of any reason why 'j' should ever be NULL, nor have I ever seen the case in the wild */
        if (likely(j)) {
                job_log(j, LOG_NOTICE, "Bug: %s:%u (%s):%u", file, line, buf, saved_errno);
        } else {
        if (likely(j)) {
                job_log(j, LOG_NOTICE, "Bug: %s:%u (%s):%u", file, line, buf, saved_errno);
        } else {
@@ -4434,26 +4931,26 @@ job_logv(job_t j, int pri, int err, const char *msg, va_list ap)
        newmsg = alloca(newmsgsz);
 
        if (err) {
        newmsg = alloca(newmsgsz);
 
        if (err) {
-       #if !TARGET_OS_EMBEDDED
+#if !TARGET_OS_EMBEDDED
                snprintf(newmsg, newmsgsz, "%s: %s", msg, strerror(err));
                snprintf(newmsg, newmsgsz, "%s: %s", msg, strerror(err));
-       #else
+#else
                snprintf(newmsg, newmsgsz, "(%s) %s: %s", label2use, msg, strerror(err));
                snprintf(newmsg, newmsgsz, "(%s) %s: %s", label2use, msg, strerror(err));
-       #endif
+#endif
        } else {
        } else {
-       #if !TARGET_OS_EMBEDDED
+#if !TARGET_OS_EMBEDDED
                snprintf(newmsg, newmsgsz, "%s", msg);
                snprintf(newmsg, newmsgsz, "%s", msg);
-       #else
+#else
                snprintf(newmsg, newmsgsz, "(%s) %s", label2use, msg);
                snprintf(newmsg, newmsgsz, "(%s) %s", label2use, msg);
-       #endif
+#endif
        }
 
        }
 
-       if( j && unlikely(j->debug) ) {
+       if (j && unlikely(j->debug)) {
                oldmask = setlogmask(LOG_UPTO(LOG_DEBUG));
        }
 
        runtime_vsyslog(&attr, newmsg, ap);
 
                oldmask = setlogmask(LOG_UPTO(LOG_DEBUG));
        }
 
        runtime_vsyslog(&attr, newmsg, ap);
 
-       if( j && unlikely(j->debug) ) {
+       if (j && unlikely(j->debug)) {
                setlogmask(oldmask);
        }
 }
                setlogmask(oldmask);
        }
 }
@@ -4540,7 +5037,7 @@ semaphoreitem_ignore(job_t j, struct semaphoreitem *si)
 {
        if (si->fd != -1) {
                job_log(j, LOG_DEBUG, "Ignoring Vnode: %d", si->fd);
 {
        if (si->fd != -1) {
                job_log(j, LOG_DEBUG, "Ignoring Vnode: %d", si->fd);
-               job_assumes(j, kevent_mod(si->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL) != -1);
+               (void)job_assumes(j, kevent_mod(si->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL) != -1);
        }
 }
 
        }
 }
 
@@ -4576,7 +5073,7 @@ semaphoreitem_watch(job_t j, struct semaphoreitem *si)
        do {
                if (si->fd == -1) {
                        struct stat sb;
        do {
                if (si->fd == -1) {
                        struct stat sb;
-                       if( stat(si->what, &sb) == 0 ) {
+                       if (stat(si->what, &sb) == 0) {
                                /* If we're watching a character or block device, only watch the parent directory. 
                                 * See rdar://problem/6489900 for the gory details. Basically, holding an open file
                                 * descriptor to a devnode could end up (a) blocking us on open(2) until someone else
                                /* If we're watching a character or block device, only watch the parent directory. 
                                 * See rdar://problem/6489900 for the gory details. Basically, holding an open file
                                 * descriptor to a devnode could end up (a) blocking us on open(2) until someone else
@@ -4589,12 +5086,12 @@ semaphoreitem_watch(job_t j, struct semaphoreitem *si)
                                 * for dev nodes by only watching the parent directory and stat(2)ing our desired file
                                 * each time the parent changes to see if it appeared or disappeared.
                                 */
                                 * for dev nodes by only watching the parent directory and stat(2)ing our desired file
                                 * each time the parent changes to see if it appeared or disappeared.
                                 */
-                               if( S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode) ) {
+                               if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode)) {
                                        si->fd = _fd(open(si->what, O_EVTONLY | O_NOCTTY | O_NONBLOCK));
                                }
                        }
                        
                                        si->fd = _fd(open(si->what, O_EVTONLY | O_NOCTTY | O_NONBLOCK));
                                }
                        }
                        
-                       if( si->fd == -1 ) {
+                       if (si->fd == -1) {
                                si->watching_parent = job_assumes(j, (si->fd = _fd(open(parentdir, O_EVTONLY | O_NOCTTY | O_NONBLOCK))) != -1);
                        } else {
                                si->watching_parent = false;
                                si->watching_parent = job_assumes(j, (si->fd = _fd(open(parentdir, O_EVTONLY | O_NOCTTY | O_NONBLOCK))) != -1);
                        } else {
                                si->watching_parent = false;
@@ -4615,7 +5112,7 @@ semaphoreitem_watch(job_t j, struct semaphoreitem *si)
                         * attached to short lived zombie processes after fork()
                         * but before kevent().
                         */
                         * attached to short lived zombie processes after fork()
                         * but before kevent().
                         */
-                       job_assumes(j, runtime_close(si->fd) == 0);
+                       (void)job_assumes(j, runtime_close(si->fd) == 0);
                        si->fd = -1;
                }
        } while (unlikely((si->fd == -1) && (saved_errno == ENOENT)));
                        si->fd = -1;
                }
        } while (unlikely((si->fd == -1) && (saved_errno == ENOENT)));
@@ -4630,7 +5127,7 @@ semaphoreitem_watch(job_t j, struct semaphoreitem *si)
 
                if (!j->poll_for_vfs_changes) {
                        j->poll_for_vfs_changes = true;
 
                if (!j->poll_for_vfs_changes) {
                        j->poll_for_vfs_changes = true;
-                       job_assumes(j, kevent_mod((uintptr_t)&j->semaphores, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, 3, j) != -1);
+                       (void)job_assumes(j, kevent_mod((uintptr_t)&j->semaphores, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, 3, j) != -1);
                }
        }
 }
                }
        }
 }
@@ -4684,19 +5181,19 @@ semaphoreitem_callback(job_t j, struct kevent *kev)
 
        if (invalidation_reason[0]) {
                job_log(j, LOG_DEBUG, "Path %s: %s", invalidation_reason, si->what);
 
        if (invalidation_reason[0]) {
                job_log(j, LOG_DEBUG, "Path %s: %s", invalidation_reason, si->what);
-               job_assumes(j, runtime_close(si->fd) == 0);
+               (void)job_assumes(j, runtime_close(si->fd) == 0);
                si->fd = -1; /* this will get fixed in semaphoreitem_watch() */
        }
 
                si->fd = -1; /* this will get fixed in semaphoreitem_watch() */
        }
 
-       if( !si->watching_parent ) {
+       if (!si->watching_parent) {
                if (si->why == PATH_CHANGES) {
                        j->start_pending = true;
                } else {
                        semaphoreitem_watch(j, si);
                }
        } else { /* Something happened to the parent directory. See if our target file appeared. */
                if (si->why == PATH_CHANGES) {
                        j->start_pending = true;
                } else {
                        semaphoreitem_watch(j, si);
                }
        } else { /* Something happened to the parent directory. See if our target file appeared. */
-               if( !invalidation_reason[0] ) {
-                       job_assumes(j, runtime_close(si->fd) == 0);
+               if (!invalidation_reason[0]) {
+                       (void)job_assumes(j, runtime_close(si->fd) == 0);
                        si->fd = -1; /* this will get fixed in semaphoreitem_watch() */
                        semaphoreitem_watch(j, si);
                }
                        si->fd = -1; /* this will get fixed in semaphoreitem_watch() */
                        semaphoreitem_watch(j, si);
                }
@@ -4730,35 +5227,35 @@ calendarinterval_new_from_obj_dict_walk(launch_data_t obj, const char *key, void
        if (val < 0) {
                job_log(j, LOG_WARNING, "The interval for key \"%s\" is less than zero.", key);
        } else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_MINUTE) == 0) {
        if (val < 0) {
                job_log(j, LOG_WARNING, "The interval for key \"%s\" is less than zero.", key);
        } else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_MINUTE) == 0) {
-               if( val > 59 ) {
+               if (val > 59) {
                        job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 59 (inclusive).", key);
                        tmptm->tm_sec = -1;
                } else {
                        tmptm->tm_min = (typeof(tmptm->tm_min)) val;
                }
        } else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_HOUR) == 0) {
                        job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 59 (inclusive).", key);
                        tmptm->tm_sec = -1;
                } else {
                        tmptm->tm_min = (typeof(tmptm->tm_min)) val;
                }
        } else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_HOUR) == 0) {
-               if( val > 23 ) {
+               if (val > 23) {
                        job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 23 (inclusive).", key);
                        tmptm->tm_sec = -1;
                } else {
                        tmptm->tm_hour = (typeof(tmptm->tm_hour)) val;
                }
        } else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_DAY) == 0) {
                        job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 23 (inclusive).", key);
                        tmptm->tm_sec = -1;
                } else {
                        tmptm->tm_hour = (typeof(tmptm->tm_hour)) val;
                }
        } else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_DAY) == 0) {
-               if( val < 1 || val > 31 ) {
+               if (val < 1 || val > 31) {
                        job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 1 and 31 (inclusive).", key);
                        tmptm->tm_sec = -1;
                } else {
                        tmptm->tm_mday = (typeof(tmptm->tm_mday)) val;
                }
        } else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_WEEKDAY) == 0) {
                        job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 1 and 31 (inclusive).", key);
                        tmptm->tm_sec = -1;
                } else {
                        tmptm->tm_mday = (typeof(tmptm->tm_mday)) val;
                }
        } else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_WEEKDAY) == 0) {
-               if( val > 7 ) {
+               if (val > 7) {
                        job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 7 (inclusive).", key);
                        tmptm->tm_sec = -1;
                } else {
                        tmptm->tm_wday = (typeof(tmptm->tm_wday)) val;
                }
        } else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_MONTH) == 0) {
                        job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 7 (inclusive).", key);
                        tmptm->tm_sec = -1;
                } else {
                        tmptm->tm_wday = (typeof(tmptm->tm_wday)) val;
                }
        } else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_MONTH) == 0) {
-               if( val > 12 ) {
+               if (val > 12) {
                        job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 12 (inclusive).", key);
                        tmptm->tm_sec = -1;
                } else {
                        job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 12 (inclusive).", key);
                        tmptm->tm_sec = -1;
                } else {
@@ -4838,7 +5335,7 @@ calendarinterval_sanity_check(void)
        time_t now = time(NULL);
 
        if (unlikely(ci && (ci->when_next < now))) {
        time_t now = time(NULL);
 
        if (unlikely(ci && (ci->when_next < now))) {
-               jobmgr_assumes(root_jobmgr, raise(SIGUSR1) != -1);
+               (void)jobmgr_assumes(root_jobmgr, raise(SIGUSR1) != -1);
        }
 }
 
        }
 }
 
@@ -4905,11 +5402,11 @@ socketgroup_delete(job_t j, struct socketgroup *sg)
                /* 5480306 */
                if (job_assumes(j, getsockname(sg->fds[i], (struct sockaddr *)&ss, &ss_len) != -1)
                                && job_assumes(j, ss_len > 0) && (ss.ss_family == AF_UNIX)) {
                /* 5480306 */
                if (job_assumes(j, getsockname(sg->fds[i], (struct sockaddr *)&ss, &ss_len) != -1)
                                && job_assumes(j, ss_len > 0) && (ss.ss_family == AF_UNIX)) {
-                       job_assumes(j, unlink(sun->sun_path) != -1);
+                       (void)job_assumes(j, unlink(sun->sun_path) != -1);
                        /* We might conditionally need to delete a directory here */
                }
 #endif
                        /* We might conditionally need to delete a directory here */
                }
 #endif
-               job_assumes(j, runtime_close(sg->fds[i]) != -1);
+               (void)job_assumes(j, runtime_close(sg->fds[i]) != -1);
        }
 
        SLIST_REMOVE(&j->sockets, sg, socketgroup, sle);
        }
 
        SLIST_REMOVE(&j->sockets, sg, socketgroup, sle);
@@ -4938,12 +5435,12 @@ socketgroup_kevent_mod(job_t j, struct socketgroup *sg, bool do_add)
 
        job_log(j, LOG_DEBUG, "%s Sockets:%s", do_add ? "Watching" : "Ignoring", buf);
 
 
        job_log(j, LOG_DEBUG, "%s Sockets:%s", do_add ? "Watching" : "Ignoring", buf);
 
-       job_assumes(j, kevent_bulk_mod(kev, sg->fd_cnt) != -1);
+       (void)job_assumes(j, kevent_bulk_mod(kev, sg->fd_cnt) != -1);
 
        for (i = 0; i < sg->fd_cnt; i++) {
 
        for (i = 0; i < sg->fd_cnt; i++) {
-               job_assumes(j, kev[i].flags & EV_ERROR);
+               (void)job_assumes(j, kev[i].flags & EV_ERROR);
                errno = (typeof(errno)) kev[i].data;
                errno = (typeof(errno)) kev[i].data;
-               job_assumes(j, kev[i].data == 0);
+               (void)job_assumes(j, kev[i].data == 0);
        }
 }
 
        }
 }
 
@@ -5017,7 +5514,7 @@ envitem_setup(launch_data_t obj, const char *key, void *context)
                return;
        }
 
                return;
        }
 
-       if( strncmp(LAUNCHD_TRUSTED_FD_ENV, key, sizeof(LAUNCHD_TRUSTED_FD_ENV) - 1) != 0 ) {
+       if (strncmp(LAUNCHD_TRUSTED_FD_ENV, key, sizeof(LAUNCHD_TRUSTED_FD_ENV) - 1) != 0) {
                envitem_new(j, key, launch_data_get_string(obj), j->importing_global_env, false);
        } else {
                job_log(j, LOG_DEBUG, "Ignoring reserved environmental variable: %s", key);
                envitem_new(j, key, launch_data_get_string(obj), j->importing_global_env, false);
        } else {
                job_log(j, LOG_DEBUG, "Ignoring reserved environmental variable: %s", key);
@@ -5033,7 +5530,7 @@ envitem_setup_one_shot(launch_data_t obj, const char *key, void *context)
                return;
        }
        
                return;
        }
        
-       if( strncmp(LAUNCHD_TRUSTED_FD_ENV, key, sizeof(LAUNCHD_TRUSTED_FD_ENV) - 1) != 0 ) {
+       if (strncmp(LAUNCHD_TRUSTED_FD_ENV, key, sizeof(LAUNCHD_TRUSTED_FD_ENV) - 1) != 0) {
                envitem_new(j, key, launch_data_get_string(obj), j->importing_global_env, true);
        } else {
                job_log(j, LOG_DEBUG, "Ignoring reserved environmental variable: %s", key);
                envitem_new(j, key, launch_data_get_string(obj), j->importing_global_env, true);
        } else {
                job_log(j, LOG_DEBUG, "Ignoring reserved environmental variable: %s", key);
@@ -5141,12 +5638,12 @@ job_useless(job_t j)
        } else if (j->removal_pending) {
                job_log(j, LOG_DEBUG, "Exited while removal was pending.");
                return true;
        } else if (j->removal_pending) {
                job_log(j, LOG_DEBUG, "Exited while removal was pending.");
                return true;
-       } else if (j->mgr->shutting_down && (j->hopefully_exits_first || j->mgr->hopefully_first_cnt == 0)) {
+       } else if (j->shutdown_monitor) {
+               return false;
+       } else if (j->mgr->shutting_down) {
                job_log(j, LOG_DEBUG, "Exited while shutdown in progress. Processes remaining: %lu/%lu", total_children, total_anon_children);
                job_log(j, LOG_DEBUG, "Exited while shutdown in progress. Processes remaining: %lu/%lu", total_children, total_anon_children);
-               if( total_children == 0 && !j->anonymous ) {
-                       job_log(j, LOG_DEBUG | LOG_CONSOLE, "Job was last (non-anonymous) to exit during %s shutdown.", (pid1_magic && j->mgr == root_jobmgr) ? "system" : "job manager");
-               } else if( total_anon_children == 0 && j->anonymous ) {
-                       job_log(j, LOG_DEBUG | LOG_CONSOLE, "Job was last (anonymous) to exit during %s shutdown.", (pid1_magic && j->mgr == root_jobmgr) ? "system" : "job manager");
+               if (total_children == 0 && !j->anonymous) {
+                       job_log(j, LOG_DEBUG | LOG_CONSOLE, "Job was last to exit during shutdown of: %s.", j->mgr->name);
                }
                return true;
        } else if (j->legacy_mach_job) {
                }
                return true;
        } else if (j->legacy_mach_job) {
@@ -5157,6 +5654,18 @@ job_useless(job_t j)
                        job_log(j, LOG_WARNING, "Failed to check-in!");
                        return true;
                }
                        job_log(j, LOG_WARNING, "Failed to check-in!");
                        return true;
                }
+       } else {
+               /* If the job's executable does not have any valid architectures (for
+                * example, if it's a PowerPC-only job), then we don't even bother
+                * trying to relaunch it, as we have no reasonable expectation that
+                * the situation will change.
+                *
+                * <rdar://problem/9106979>
+                */
+               if (!j->did_exec && WEXITSTATUS(j->last_exit_status) == EBADARCH) {
+                       job_log(j, LOG_ERR, "Job executable does not contain supported architectures. Unloading it. Its plist should be removed.");
+                       return true;
+               }
        }
 
        return false;
        }
 
        return false;
@@ -5187,7 +5696,7 @@ job_keepalive(job_t j)
                return false;
        }
 
                return false;
        }
 
-       if( unlikely(j->needs_kickoff) ) {
+       if (unlikely(j->needs_kickoff)) {
                job_log(j, LOG_DEBUG, "KeepAlive check: Job needs to be kicked off on-demand before KeepAlive sets in.");
                return false;
        }
                job_log(j, LOG_DEBUG, "KeepAlive check: Job needs to be kicked off on-demand before KeepAlive sets in.");
                return false;
        }
@@ -5214,8 +5723,17 @@ job_keepalive(job_t j)
                        return true;
                }
        }
                        return true;
                }
        }
-
-
+       
+       /* TODO: Coalesce external events and semaphore items, since they're basically
+        * the same thing.
+        */
+       struct externalevent *ei = NULL;
+       LIST_FOREACH(ei, &j->events, job_le) {
+               if (ei->state == ei->wanted_state) {
+                       return true;
+               }
+       }
+       
        SLIST_FOREACH(si, &j->semaphores, sle) {
                bool wanted_state = false;
                int qdir_file_cnt;
        SLIST_FOREACH(si, &j->semaphores, sle) {
                bool wanted_state = false;
                int qdir_file_cnt;
@@ -5238,10 +5756,17 @@ job_keepalive(job_t j)
                                return true;
                        }
                        break;
                                return true;
                        }
                        break;
+               case CRASHED:
+                       wanted_state = true;
+               case DID_NOT_CRASH:
+                       if (j->crashed == wanted_state) {
+                               return true;
+                       }
+                       break;
                case OTHER_JOB_ENABLED:
                        wanted_state = true;
                case OTHER_JOB_DISABLED:
                case OTHER_JOB_ENABLED:
                        wanted_state = true;
                case OTHER_JOB_DISABLED:
-                       if ((bool)job_find(si->what) == wanted_state) {
+                       if ((bool)job_find(NULL, si->what) == wanted_state) {
                                job_log(j, LOG_DEBUG, "KeepAlive: The following job is %s: %s", wanted_state ? "enabled" : "disabled", si->what);
                                return true;
                        }
                                job_log(j, LOG_DEBUG, "KeepAlive: The following job is %s: %s", wanted_state ? "enabled" : "disabled", si->what);
                                return true;
                        }
@@ -5249,7 +5774,7 @@ job_keepalive(job_t j)
                case OTHER_JOB_ACTIVE:
                        wanted_state = true;
                case OTHER_JOB_INACTIVE:
                case OTHER_JOB_ACTIVE:
                        wanted_state = true;
                case OTHER_JOB_INACTIVE:
-                       if ((other_j = job_find(si->what))) {
+                       if ((other_j = job_find(NULL, si->what))) {
                                if ((bool)other_j->p == wanted_state) {
                                        job_log(j, LOG_DEBUG, "KeepAlive: The following job is %s: %s", wanted_state ? "active" : "inactive", si->what);
                                        return true;
                                if ((bool)other_j->p == wanted_state) {
                                        job_log(j, LOG_DEBUG, "KeepAlive: The following job is %s: %s", wanted_state ? "active" : "inactive", si->what);
                                        return true;
@@ -5263,15 +5788,15 @@ job_keepalive(job_t j)
                                job_log(j, LOG_DEBUG, "KeepAlive: The following path %s: %s", wanted_state ? "exists" : "is missing", si->what);
                                return true;
                        } else {
                                job_log(j, LOG_DEBUG, "KeepAlive: The following path %s: %s", wanted_state ? "exists" : "is missing", si->what);
                                return true;
                        } else {
-                               if( wanted_state ) { /* File is not there but we wish it was. */
-                                       if( si->fd != -1 && !si->watching_parent ) { /* Need to be watching the parent now. */
-                                               job_assumes(j, runtime_close(si->fd) == 0);
+                               if (wanted_state) { /* File is not there but we wish it was. */
+                                       if (si->fd != -1 && !si->watching_parent) { /* Need to be watching the parent now. */
+                                               (void)job_assumes(j, runtime_close(si->fd) == 0);
                                                si->fd = -1;
                                                semaphoreitem_watch(j, si);
                                        }
                                } else { /* File is there but we wish it wasn't. */
                                                si->fd = -1;
                                                semaphoreitem_watch(j, si);
                                        }
                                } else { /* File is there but we wish it wasn't. */
-                                       if( si->fd != -1 && si->watching_parent ) { /* Need to watch the file now. */
-                                               job_assumes(j, runtime_close(si->fd) == 0);
+                                       if (si->fd != -1 && si->watching_parent) { /* Need to watch the file now. */
+                                               (void)job_assumes(j, runtime_close(si->fd) == 0);
                                                si->fd = -1;
                                                semaphoreitem_watch(j, si);
                                        }
                                                si->fd = -1;
                                                semaphoreitem_watch(j, si);
                                        }
@@ -5298,12 +5823,15 @@ const char *
 job_active(job_t j)
 {
        struct machservice *ms;
 job_active(job_t j)
 {
        struct machservice *ms;
+       if (j->p && j->shutdown_monitor) {
+               return "Monitoring shutdown";
+       }
        if (j->p) {
                return "PID is still valid";
        }
 
        if (j->mgr->shutting_down && j->log_redirect_fd) {
        if (j->p) {
                return "PID is still valid";
        }
 
        if (j->mgr->shutting_down && j->log_redirect_fd) {
-               job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
+               (void)job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
                j->log_redirect_fd = 0;
        }
 
                j->log_redirect_fd = 0;
        }
 
@@ -5311,7 +5839,7 @@ job_active(job_t j)
                if (job_assumes(j, j->legacy_LS_job)) {
                        return "Standard out/error is still valid";
                } else {
                if (job_assumes(j, j->legacy_LS_job)) {
                        return "Standard out/error is still valid";
                } else {
-                       job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
+                       (void)job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
                        j->log_redirect_fd = 0;
                }
        }
                        j->log_redirect_fd = 0;
                }
        }
@@ -5333,25 +5861,25 @@ void
 machservice_watch(job_t j, struct machservice *ms)
 {
        if (ms->recv) {
 machservice_watch(job_t j, struct machservice *ms)
 {
        if (ms->recv) {
-               job_assumes(j, runtime_add_mport(ms->port, NULL, 0) == KERN_SUCCESS);
+               (void)job_assumes(j, runtime_add_mport(ms->port, NULL, 0) == KERN_SUCCESS);
        }
 }
 
 void
 machservice_ignore(job_t j, struct machservice *ms)
 {
        }
 }
 
 void
 machservice_ignore(job_t j, struct machservice *ms)
 {
-       job_assumes(j, runtime_remove_mport(ms->port) == KERN_SUCCESS);
+       (void)job_assumes(j, runtime_remove_mport(ms->port) == KERN_SUCCESS);
 }
 
 void
 machservice_resetport(job_t j, struct machservice *ms)
 {
        LIST_REMOVE(ms, port_hash_sle);
 }
 
 void
 machservice_resetport(job_t j, struct machservice *ms)
 {
        LIST_REMOVE(ms, port_hash_sle);
-       job_assumes(j, launchd_mport_close_recv(ms->port) == KERN_SUCCESS);
-       job_assumes(j, launchd_mport_deallocate(ms->port) == KERN_SUCCESS);
+       (void)job_assumes(j, launchd_mport_close_recv(ms->port) == KERN_SUCCESS);
+       (void)job_assumes(j, launchd_mport_deallocate(ms->port) == KERN_SUCCESS);
        ms->gen_num++;
        ms->gen_num++;
-       job_assumes(j, launchd_mport_create_recv(&ms->port) == KERN_SUCCESS);
-       job_assumes(j, launchd_mport_make_send(ms->port) == KERN_SUCCESS);
+       (void)job_assumes(j, launchd_mport_create_recv(&ms->port) == KERN_SUCCESS);
+       (void)job_assumes(j, launchd_mport_make_send(ms->port) == KERN_SUCCESS);
        LIST_INSERT_HEAD(&port_hash[HASH_PORT(ms->port)], ms, port_hash_sle);
 }
 
        LIST_INSERT_HEAD(&port_hash[HASH_PORT(ms->port)], ms, port_hash_sle);
 }
 
@@ -5385,28 +5913,57 @@ machservice_new(job_t j, const char *name, mach_port_t *serviceport, bool pid_lo
        }
 
        SLIST_INSERT_HEAD(&j->machservices, ms, sle);
        }
 
        SLIST_INSERT_HEAD(&j->machservices, ms, sle);
-       
-       jobmgr_t jm_to_insert = j->mgr;
-       if( g_flat_mach_namespace ) {
-               jm_to_insert = (j->mgr->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) ? j->mgr : root_jobmgr;
+
+       jobmgr_t where2put = j->mgr;
+       /* XPC domains are separate from Mach bootstraps. */
+       if (!(j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
+               if (g_flat_mach_namespace && !(j->mgr->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET)) {
+                       where2put = root_jobmgr;
+               }
        }
        
        }
        
-       LIST_INSERT_HEAD(&jm_to_insert->ms_hash[hash_ms(ms->name)], ms, name_hash_sle); 
+       /* Don't allow MachServices added by multiple-instance jobs to be looked up by others.
+        * We could just do this with a simple bit, but then we'd have to uniquify the
+        * names ourselves to avoid collisions. This is just easier.
+        */
+       if (!j->dedicated_instance) {
+               LIST_INSERT_HEAD(&where2put->ms_hash[hash_ms(ms->name)], ms, name_hash_sle);    
+       }
        LIST_INSERT_HEAD(&port_hash[HASH_PORT(ms->port)], ms, port_hash_sle);
 
        job_log(j, LOG_DEBUG, "Mach service added%s: %s", (j->mgr->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) ? " to private namespace" : "", name);
 
        return ms;
 out_bad2:
        LIST_INSERT_HEAD(&port_hash[HASH_PORT(ms->port)], ms, port_hash_sle);
 
        job_log(j, LOG_DEBUG, "Mach service added%s: %s", (j->mgr->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) ? " to private namespace" : "", name);
 
        return ms;
 out_bad2:
-       job_assumes(j, launchd_mport_close_recv(ms->port) == KERN_SUCCESS);
+       (void)job_assumes(j, launchd_mport_close_recv(ms->port) == KERN_SUCCESS);
 out_bad:
        free(ms);
        return NULL;
 }
 
 out_bad:
        free(ms);
        return NULL;
 }
 
+#ifndef __LAUNCH_DISABLE_XPC_SUPPORT__
+struct machservice *
+machservice_new_alias(job_t j, struct machservice *orig)
+{
+       struct machservice *ms = calloc(1, sizeof(struct machservice) + strlen(orig->name) + 1);
+       if (job_assumes(j, ms != NULL)) {
+               strcpy((char *)ms->name, orig->name);
+               ms->alias = orig;
+               ms->job = j;
+
+               LIST_INSERT_HEAD(&j->mgr->ms_hash[hash_ms(ms->name)], ms, name_hash_sle);
+               SLIST_INSERT_HEAD(&j->machservices, ms, sle);
+               jobmgr_log(j->mgr, LOG_DEBUG, "Service aliased into job manager: %s", orig->name);
+       }
+
+       return ms;
+}
+#endif
+
 bootstrap_status_t
 machservice_status(struct machservice *ms)
 {
 bootstrap_status_t
 machservice_status(struct machservice *ms)
 {
+       ms = ms->alias ? ms->alias : ms;
        if (ms->isActive) {
                return BOOTSTRAP_STATUS_ACTIVE;
        } else if (ms->job->ondemand) {
        if (ms->isActive) {
                return BOOTSTRAP_STATUS_ACTIVE;
        } else if (ms->job->ondemand) {
@@ -5447,10 +6004,10 @@ job_setup_exception_port(job_t j, task_t target_task)
 #endif
 
        if (likely(target_task)) {
 #endif
 
        if (likely(target_task)) {
-               job_assumes(j, task_set_exception_ports(target_task, EXC_MASK_CRASH, exc_port, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, f) == KERN_SUCCESS);
+               (void)job_assumes(j, task_set_exception_ports(target_task, EXC_MASK_CRASH, exc_port, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, f) == KERN_SUCCESS);
        } else if (pid1_magic && the_exception_server) {
                mach_port_t mhp = mach_host_self();
        } else if (pid1_magic && the_exception_server) {
                mach_port_t mhp = mach_host_self();
-               job_assumes(j, host_set_exception_ports(mhp, EXC_MASK_CRASH, the_exception_server, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, f) == KERN_SUCCESS);
+               (void)job_assumes(j, host_set_exception_ports(mhp, EXC_MASK_CRASH, the_exception_server, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, f) == KERN_SUCCESS);
                job_assumes(j, launchd_mport_deallocate(mhp) == KERN_SUCCESS);
        }
 }
                job_assumes(j, launchd_mport_deallocate(mhp) == KERN_SUCCESS);
        }
 }
@@ -5499,7 +6056,7 @@ machservice_setup_options(launch_data_t obj, const char *key, void *context)
                        }
                } else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_HOSTSPECIALPORT) == 0 && pid1_magic) {
                        if (which_port > HOST_MAX_SPECIAL_KERNEL_PORT) {
                        }
                } else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_HOSTSPECIALPORT) == 0 && pid1_magic) {
                        if (which_port > HOST_MAX_SPECIAL_KERNEL_PORT) {
-                               job_assumes(ms->job, (errno = host_set_special_port(mhp, which_port, ms->port)) == KERN_SUCCESS);
+                               (void)job_assumes(ms->job, (errno = host_set_special_port(mhp, which_port, ms->port)) == KERN_SUCCESS);
                        } else {
                                job_log(ms->job, LOG_WARNING, "Tried to set a reserved host special port: %d", which_port);
                        }
                        } else {
                                job_log(ms->job, LOG_WARNING, "Tried to set a reserved host special port: %d", which_port);
                        }
@@ -5516,15 +6073,17 @@ machservice_setup_options(launch_data_t obj, const char *key, void *context)
                        job_set_exception_port(ms->job, ms->port);
                } else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_KUNCSERVER) == 0) {
                        ms->kUNCServer = b;
                        job_set_exception_port(ms->job, ms->port);
                } else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_KUNCSERVER) == 0) {
                        ms->kUNCServer = b;
-                       job_assumes(ms->job, host_set_UNDServer(mhp, ms->port) == KERN_SUCCESS);
+                       (void)job_assumes(ms->job, host_set_UNDServer(mhp, ms->port) == KERN_SUCCESS);
+               } else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_PINGEVENTUPDATES) == 0) {
+                       ms->event_update_port = b;
                }
                break;
        case LAUNCH_DATA_STRING:
                }
                break;
        case LAUNCH_DATA_STRING:
-               if( strcasecmp(key, LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH) == 0 ) {
+               if (strcasecmp(key, LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH) == 0) {
                        const char *option = launch_data_get_string(obj);
                        const char *option = launch_data_get_string(obj);
-                       if( strcasecmp(option, "One") == 0 ) {
+                       if (strcasecmp(option, "One") == 0) {
                                ms->drain_one_on_crash = true;
                                ms->drain_one_on_crash = true;
-                       } else if( strcasecmp(option, "All") == 0 ) {
+                       } else if (strcasecmp(option, "All") == 0) {
                                ms->drain_all_on_crash = true;
                        }
                }
                                ms->drain_all_on_crash = true;
                        }
                }
@@ -5556,7 +6115,8 @@ machservice_setup(launch_data_t obj, const char *key, void *context)
        }
 
        ms->isActive = false;
        }
 
        ms->isActive = false;
-
+       ms->upfront = true;
+       
        if (launch_data_get_type(obj) == LAUNCH_DATA_DICTIONARY) {
                launch_data_dict_iterate(obj, machservice_setup_options, ms);
        }
        if (launch_data_get_type(obj) == LAUNCH_DATA_DICTIONARY) {
                launch_data_dict_iterate(obj, machservice_setup_options, ms);
        }
@@ -5570,96 +6130,94 @@ jobmgr_do_garbage_collection(jobmgr_t jm)
                jobmgr_do_garbage_collection(jmi);
        }
 
                jobmgr_do_garbage_collection(jmi);
        }
 
-       if( !jm->shutting_down ) {
+       if (!jm->shutting_down) {
                return jm;
        }
        
                return jm;
        }
        
-       if( SLIST_EMPTY(&jm->submgrs) ) {
+       if (SLIST_EMPTY(&jm->submgrs)) {
                jobmgr_log(jm, LOG_DEBUG, "No submanagers left.");
        } else {
                jobmgr_log(jm, LOG_DEBUG, "Still have submanagers.");
        }
                jobmgr_log(jm, LOG_DEBUG, "No submanagers left.");
        } else {
                jobmgr_log(jm, LOG_DEBUG, "Still have submanagers.");
        }
-       
-       int phase = -1;
-       for( phase = jm->shutdown_phase; phase < JOBMGR_PHASE_LAST; phase++ ) {
-               if( phase == JOBMGR_PHASE_HOPEFULLY_EXITS_LAST ) {
-                       if( jm == root_jobmgr ) {
-                               simulate_pid1_crash();
-                       }
-                       
-                       if( jm == root_jobmgr && pid1_magic && !jm->killed_stray_jobs ) {
-                               jobmgr_log_stray_children(jm, true);
-                               jm->killed_stray_jobs = true;
-                       }
+
+       size_t actives = 0;
+       job_t ji = NULL, jn = NULL;
+       LIST_FOREACH_SAFE(ji, &jm->jobs, sle, jn) {
+               if (ji->anonymous) {
+                       continue;
+               }
+               
+               /* Let the shutdown monitor be up until the very end. */
+               if (ji->shutdown_monitor) {
+                       continue;
                }
 
                }
 
-               uint32_t unkilled_cnt = 0;
-               job_t ji = NULL, jn = NULL;
-               LIST_FOREACH_SAFE( ji, &jm->jobs, sle, jn ) {
-                       if( phase == JOBMGR_PHASE_HOPEFULLY_EXITS_FIRST && !ji->hopefully_exits_first ) {
-                               continue;
-                       } else if( phase == JOBMGR_PHASE_NORMAL ) {
-                               if( ji->holds_ref ) {
-                                       /* If we're shutting down, release the hold holds_ref jobs
-                                        * have on us.
-                                        */
-                                       job_remove(ji);                 
-                               }
-                               
-                               if( ji->hopefully_exits_first || ji->hopefully_exits_last ) {
-                                       continue;
-                               }
-                       } else if( phase == JOBMGR_PHASE_HOPEFULLY_EXITS_LAST && !ji->hopefully_exits_last ) {
-                               continue;
-                       }
-                       
-                       if( ji->anonymous ) {
-                               continue;
+               /* On our first pass through, open a transaction for all the jobs that
+                * need to be dirty at shutdown. We'll close these transactions once the
+                * jobs that do not need to be dirty at shutdown have all exited.
+                */
+               if (ji->dirty_at_shutdown && !jm->shutdown_jobs_dirtied) {
+                       job_open_shutdown_transaction(ji);
+               }
+
+               const char *active = job_active(ji);
+               if (!active) {
+                       job_remove(ji);
+               } else {
+                       job_log(ji, LOG_DEBUG, "Job is active: %s", active);
+                       job_stop(ji);
+
+                       if (ji->p && !ji->dirty_at_shutdown) {
+                               /* We really only care if the job has not yet been reaped.
+                                * There's no reason to delay shutdown if a Mach port has not
+                                * yet been sent back to us, for example. While we're shutting
+                                * all the "normal" jobs down, do not count the
+                                * dirty-at-shutdown jobs toward the total of actives.
+                                *
+                                * Note that there's a potential race here where we may not get
+                                * a port back in time, so that when we hit jobmgr_remove(), we
+                                * end up removing the job and then our attempt to close the
+                                * Mach port will fail. But at that point, the failure won't
+                                * even make it to the syslog, so not a big deal.
+                                */
+                               actives++;
                        }
                        }
-                       
-                       const char *active = job_active(ji);
-                       if( !active ) {
-                               job_log(ji, LOG_DEBUG, "Job is inactive. Removing.");
-                               job_remove(ji);
+
+                       if (ji->clean_kill) {
+                               job_log(ji, LOG_DEBUG, "Job was killed cleanly.");
                        } else {
                        } else {
-                               if( ji->p ) {
-                                       if( !ji->stopped ) {
-                                               job_log(ji, LOG_DEBUG, "Stopping job.");
-                                               job_stop(ji);
-                                               unkilled_cnt++;
-                                       } else {
-                                               if( ji->clean_kill ) {
-                                                       job_log(ji, LOG_DEBUG, "Job was clean and sent SIGKILL.");
-                                                       if( !ji->clean_exit_timer_expired ) {
-                                                               /* Give jobs that were clean and sent SIGKILL 1 second to exit after receipt. */
-                                                               unkilled_cnt++;
-                                                       } else {
-                                                               job_log(ji, LOG_ERR, "Job was clean, killed and has not exited after 1 second. Moving on.");
-                                                       }
-                                               } else {
-                                                       job_log(ji, LOG_DEBUG, "Job was sent SIGTERM%s.", ji->sent_sigkill ? " and SIGKILL" : "");
-                                                       unkilled_cnt += !ji->sent_sigkill;
-                                               }
-                                       }
-                               } else {
-                                       job_log(ji, LOG_DEBUG, "Job is active: %s", active);
+                               job_log(ji, LOG_DEBUG, "Job was sent SIGTERM%s.", ji->sent_sigkill ? " and SIGKILL" : "");
+                       }
+               }
+       }
+
+       jm->shutdown_jobs_dirtied = true;
+       if (actives == 0) {
+               if (!jm->shutdown_jobs_cleaned) {
+                       LIST_FOREACH(ji, &jm->jobs, sle) {
+                               if (!ji->anonymous) {
+                                       job_close_shutdown_transaction(ji);
+                                       actives++;
                                }
                        }
                                }
                        }
-               } /* LIST_FOREACH_SAFE */
-               
-               if( unkilled_cnt == 0 ) {
-                       jobmgr_log(jm, LOG_DEBUG, "Done with the %s bucket, advancing.", s_phases[jm->shutdown_phase]);
-                       jm->shutdown_phase++;
-               } else {
-                       jobmgr_log(jm, LOG_DEBUG, "Still %u unkilled job%s in %s bucket.", unkilled_cnt, unkilled_cnt > 1 ? "s" : "", s_phases[jm->shutdown_phase]);
-                       phase = JOBMGR_PHASE_LAST;
+
+                       jm->shutdown_jobs_cleaned = true;
+               } else if (jm->monitor_shutdown && _s_shutdown_monitor) {
+                       /* The rest of shutdown has completed, so we can kill the shutdown
+                        * monitor now like it was any other job.
+                        */
+                       _s_shutdown_monitor->shutdown_monitor = false;
+                       actives = 1;
+
+                       job_log(_s_shutdown_monitor, LOG_NOTICE | LOG_CONSOLE, "Stopping shutdown monitor.");
+                       job_stop(_s_shutdown_monitor);
+                       _s_shutdown_monitor = NULL;
                }
                }
-       } /* for */
-       
+       }
+
        jobmgr_t r = jm;
        jobmgr_t r = jm;
-       if( jm->shutdown_phase > JOBMGR_PHASE_HOPEFULLY_EXITS_LAST && SLIST_EMPTY(&jm->submgrs) ) {
+       if (SLIST_EMPTY(&jm->submgrs) && actives == 0) {
                jobmgr_log(jm, LOG_DEBUG, "Removing.");
                jobmgr_log(jm, LOG_DEBUG, "Removing.");
-               jobmgr_log_stray_children(jm, false);
                jobmgr_remove(jm);
                r = NULL;
        }
                jobmgr_remove(jm);
                r = NULL;
        }
@@ -5670,7 +6228,6 @@ jobmgr_do_garbage_collection(jobmgr_t jm)
 void
 jobmgr_kill_stray_children(jobmgr_t jm, pid_t *p, size_t np)
 {
 void
 jobmgr_kill_stray_children(jobmgr_t jm, pid_t *p, size_t np)
 {
-#if 1
        /* I maintain that stray processes should be at the mercy of launchd during shutdown,
         * but nevertheless, things like diskimages-helper can stick around, and SIGKILLing 
         * them can result in data loss. So we send SIGTERM to all the strays and don't wait
        /* I maintain that stray processes should be at the mercy of launchd during shutdown,
         * but nevertheless, things like diskimages-helper can stick around, and SIGKILLing 
         * them can result in data loss. So we send SIGTERM to all the strays and don't wait
@@ -5679,125 +6236,71 @@ jobmgr_kill_stray_children(jobmgr_t jm, pid_t *p, size_t np)
         * See rdar://problem/6562592
         */
        size_t i = 0;
         * See rdar://problem/6562592
         */
        size_t i = 0;
-       for( i = 0; i < np; i++ ) {
-               if( p[i] != 0 ) {
+       for (i = 0; i < np; i++) {
+               if (p[i] != 0) {
                        jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Sending SIGTERM to PID %u and continuing...", p[i]);
                        jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Sending SIGTERM to PID %u and continuing...", p[i]);
-                       jobmgr_assumes(jm, runtime_kill(p[i], SIGTERM) != -1);
-               }
-       }
-#else
-       struct timespec tts = { 2, 0 }; /* Wait 2 seconds for stray children to die after being SIGTERM'ed. */
-       struct timespec kts = { 1, 0 }; /* Wait 1 second for stray children to die after being SIGKILL'ed. */
-       uint64_t start, end, nanosec;
-       struct kevent kev;
-       int r, kq = kqueue();
-       
-       if (!jobmgr_assumes(jm, kq != -1)) {
-               return;
-       }
-
-       start = runtime_get_opaque_time();
-       size_t i = 0, n2t = 0;
-       for( i = 0; i < np; i++ ) {
-               if( p[i] != 0 ) {
-                       EV_SET(&kev, p[i], EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, 0);
-                       
-                       if( jobmgr_assumes(jm, kevent(kq, &kev, 1, NULL, 0, NULL) != -1) ) {
-                               jobmgr_assumes(jm, runtime_kill(p[i], SIGTERM) != -1);
-                               n2t++;
-                       } else {
-                               jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Disregarding PID %u and continuing.", p[i]);
-                               p[i] = 0;
-                       }
-               }
-       }
-
-       while( n2t > 0 && (r = kevent(kq, NULL, 0, &kev, 1, &tts)) ) {
-               int status = 0;
-               waitpid((pid_t)kev.ident, &status, WNOHANG);
-               
-               end = runtime_get_opaque_time();
-               nanosec = runtime_opaque_time_to_nano(end - start);
-               jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "PID %u died after %llu nanoseconds.", (pid_t)kev.ident, nanosec);
-               
-               for( i = 0; i < np; i++ ) {
-                       p[i] = ( p[i] == (pid_t)kev.ident ) ? 0 : p[i];
-               }
-       }
-
-       size_t n2k = 0;
-       for( i = 0; i < np; i++ ) {
-               if( p[i] != 0 ) {
-                       jobmgr_assumes(jm, runtime_kill(p[i], SIGKILL) != -1);
-                       n2k++;
-               }
-       }
-
-       while( n2k > 0 && (r = kevent(kq, NULL, 0, &kev, 1, &kts)) ) {
-               int status = 0;
-               waitpid((pid_t)kev.ident, &status, WNOHANG);
-               
-               end = runtime_get_opaque_time();
-               nanosec = runtime_opaque_time_to_nano(end - start);
-               jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "PID %u was killed and died after %llu nanoseconds.", (pid_t)kev.ident, nanosec);
-               
-               for( i = 0; i < np; i++ ) {
-                       p[i] = ( p[i] == (pid_t)kev.ident ) ? 0 : p[i];
-               }
-       }
-       
-       for( i = 0; i < np; i++ ) {
-               if( p[i] != 0 ) {
-                       jobmgr_log(jm, LOG_NOTICE | LOG_CONSOLE, "PID %u did not die after being SIGKILL'ed 1 second ago.", p[i]);
+                       (void)jobmgr_assumes(jm, runtime_kill(p[i], SIGTERM) != -1);
                }
        }
                }
        }
-#endif
 }
 
 void
 jobmgr_log_stray_children(jobmgr_t jm, bool kill_strays)
 {
 }
 
 void
 jobmgr_log_stray_children(jobmgr_t jm, bool kill_strays)
 {
-       int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
-       size_t i, kp_cnt = 0, kp_skipped = 0, len = sizeof(struct kinfo_proc) * get_kern_max_proc();
-       struct kinfo_proc *kp;
-
+       size_t kp_skipped = 0, len = sizeof(pid_t) * get_kern_max_proc();
+       pid_t *pids = NULL;
+       int i = 0, kp_cnt = 0;
+       
        if (likely(jm->parentmgr || !pid1_magic)) {
                return;
        }
 
        if (likely(jm->parentmgr || !pid1_magic)) {
                return;
        }
 
-       if (!jobmgr_assumes(jm, (kp = malloc(len)) != NULL)) {
+       if (!jobmgr_assumes(jm, (pids = malloc(len)) != NULL)) {
                return;
        }
 
        runtime_ktrace0(RTKT_LAUNCHD_FINDING_ALL_STRAYS);
 
                return;
        }
 
        runtime_ktrace0(RTKT_LAUNCHD_FINDING_ALL_STRAYS);
 
-       if (!jobmgr_assumes(jm, sysctl(mib, 3, kp, &len, NULL, 0) != -1)) {
+       if (!jobmgr_assumes(jm, (kp_cnt = proc_listallpids(pids, len)) != -1)) {
                goto out;
        }
 
                goto out;
        }
 
-       kp_cnt = len / sizeof(struct kinfo_proc);
        pid_t *ps = (pid_t *)calloc(sizeof(pid_t), kp_cnt);
        pid_t *ps = (pid_t *)calloc(sizeof(pid_t), kp_cnt);
-       
        for (i = 0; i < kp_cnt; i++) {
        for (i = 0; i < kp_cnt; i++) {
-               pid_t p_i = kp[i].kp_proc.p_pid;
-               pid_t pp_i = kp[i].kp_eproc.e_ppid;
-               pid_t pg_i = kp[i].kp_eproc.e_pgid;
-               const char *z = (kp[i].kp_proc.p_stat == SZOMB) ? "zombie " : "";
-               const char *n = kp[i].kp_proc.p_comm;
+               struct proc_bsdshortinfo proc;
+               if (proc_pidinfo(pids[i], PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
+                       if (errno != ESRCH) {
+                               jobmgr_assumes(jm, errno == 0);
+                       }
+
+                       kp_skipped++;
+                       continue;
+               }
+               
+               pid_t p_i = pids[i];
+               pid_t pp_i = proc.pbsi_ppid;
+               pid_t pg_i = proc.pbsi_pgid;
+               const char *z = (proc.pbsi_status == SZOMB) ? "zombie " : "";
+               const char *n = proc.pbsi_comm;
 
                if (unlikely(p_i == 0 || p_i == 1)) {
                        kp_skipped++;
                        continue;
                }
 
                if (unlikely(p_i == 0 || p_i == 1)) {
                        kp_skipped++;
                        continue;
                }
+
+               if (_s_shutdown_monitor && pp_i == _s_shutdown_monitor->p) {
+                       kp_skipped++;
+                       continue;
+               }
                
                /* We might have some jobs hanging around that we've decided to shut down in spite of. */
                job_t j = jobmgr_find_by_pid(jm, p_i, false);
                
                /* We might have some jobs hanging around that we've decided to shut down in spite of. */
                job_t j = jobmgr_find_by_pid(jm, p_i, false);
-               if( !j || (j && j->anonymous) ) {
+               if (!j || (j && j->anonymous)) {
                        jobmgr_log(jm, LOG_INFO | LOG_CONSOLE, "Stray %s%s at shutdown: PID %u PPID %u PGID %u %s", z, j ? "anonymous job" : "process", p_i, pp_i, pg_i, n);
                        
                        int status = 0;
                        jobmgr_log(jm, LOG_INFO | LOG_CONSOLE, "Stray %s%s at shutdown: PID %u PPID %u PGID %u %s", z, j ? "anonymous job" : "process", p_i, pp_i, pg_i, n);
                        
                        int status = 0;
-                       if( pp_i == getpid() && !jobmgr_assumes(jm, kp[i].kp_proc.p_stat != SZOMB) ) {
-                               if( jobmgr_assumes(jm, waitpid(p_i, &status, WNOHANG) == 0) ) {
+                       if (pp_i == getpid() && !jobmgr_assumes(jm, proc.pbsi_status != SZOMB)) {
+                               if (jobmgr_assumes(jm, waitpid(p_i, &status, WNOHANG) == 0)) {
                                        jobmgr_log(jm, LOG_INFO | LOG_CONSOLE, "Unreaped zombie stray exited with status %i.", WEXITSTATUS(status));
                                }
                                kp_skipped++;
                                        jobmgr_log(jm, LOG_INFO | LOG_CONSOLE, "Unreaped zombie stray exited with status %i.", WEXITSTATUS(status));
                                }
                                kp_skipped++;
@@ -5808,7 +6311,7 @@ jobmgr_log_stray_children(jobmgr_t jm, bool kill_strays)
                                 * hints to the kernel along the way, so that it could shutdown certain subsystems when
                                 * their userspace emissaries go away, before the call to reboot(2).
                                 */
                                 * hints to the kernel along the way, so that it could shutdown certain subsystems when
                                 * their userspace emissaries go away, before the call to reboot(2).
                                 */
-                               if( leader && leader->ignore_pg_at_shutdown ) {
+                               if (leader && leader->ignore_pg_at_shutdown) {
                                        kp_skipped++;
                                } else {
                                        ps[i] = p_i;
                                        kp_skipped++;
                                } else {
                                        ps[i] = p_i;
@@ -5819,13 +6322,13 @@ jobmgr_log_stray_children(jobmgr_t jm, bool kill_strays)
                }
        }
 
                }
        }
 
-       if( (kp_cnt - kp_skipped > 0) && kill_strays ) {
-               jobmgr_kill_stray_children(jm, ps, kp_cnt);
+       if ((kp_cnt - kp_skipped > 0) && kill_strays) {
+               jobmgr_kill_stray_children(jm, ps, kp_cnt - kp_skipped);
        }
 
        free(ps);
 out:
        }
 
        free(ps);
 out:
-       free(kp);
+       free(pids);
 }
 
 jobmgr_t 
 }
 
 jobmgr_t 
@@ -5842,13 +6345,13 @@ job_uncork_fork(job_t j)
        job_log(j, LOG_DEBUG, "Uncorking the fork().");
        /* this unblocks the child and avoids a race
         * between the above fork() and the kevent_mod() */
        job_log(j, LOG_DEBUG, "Uncorking the fork().");
        /* this unblocks the child and avoids a race
         * between the above fork() and the kevent_mod() */
-       job_assumes(j, write(j->fork_fd, &c, sizeof(c)) == sizeof(c));
-       job_assumes(j, runtime_close(j->fork_fd) != -1);
+       (void)job_assumes(j, write(j->fork_fd, &c, sizeof(c)) == sizeof(c));
+       (void)job_assumes(j, runtime_close(j->fork_fd) != -1);
        j->fork_fd = 0;
 }
 
 jobmgr_t 
        j->fork_fd = 0;
 }
 
 jobmgr_t 
-jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bool sflag, const char *name, bool no_init, mach_port_t session_port)
+jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bool sflag, const char *name, bool skip_init, mach_port_t asport)
 {
        mach_msg_size_t mxmsgsz;
        job_t bootstrapper = NULL;
 {
        mach_msg_size_t mxmsgsz;
        job_t bootstrapper = NULL;
@@ -5867,6 +6370,10 @@ jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bo
                return NULL;
        }
 
                return NULL;
        }
 
+       if (jm == NULL) {
+               root_jobmgr = jmr;
+       }
+
        jmr->kqjobmgr_callback = jobmgr_callback;
        strcpy(jmr->name_init, name ? name : "Under construction");
 
        jmr->kqjobmgr_callback = jobmgr_callback;
        strcpy(jmr->name_init, name ? name : "Under construction");
 
@@ -5881,7 +6388,7 @@ jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bo
        }
 
        if (transfer_port != MACH_PORT_NULL) {
        }
 
        if (transfer_port != MACH_PORT_NULL) {
-               jobmgr_assumes(jmr, jm != NULL);
+               (void)jobmgr_assumes(jmr, jm != NULL);
                jmr->jm_port = transfer_port;
        } else if (!jm && !pid1_magic) {
                char *trusted_fd = getenv(LAUNCHD_TRUSTED_FD_ENV);
                jmr->jm_port = transfer_port;
        } else if (!jm && !pid1_magic) {
                char *trusted_fd = getenv(LAUNCHD_TRUSTED_FD_ENV);
@@ -5897,8 +6404,8 @@ jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bo
                        int dfd, lfd = (int) strtol(trusted_fd, NULL, 10);
 
                        if ((dfd = dup(lfd)) >= 0) {
                        int dfd, lfd = (int) strtol(trusted_fd, NULL, 10);
 
                        if ((dfd = dup(lfd)) >= 0) {
-                               jobmgr_assumes(jmr, runtime_close(dfd) != -1);
-                               jobmgr_assumes(jmr, runtime_close(lfd) != -1);
+                               (void)jobmgr_assumes(jmr, runtime_close(dfd) != -1);
+                               (void)jobmgr_assumes(jmr, runtime_close(lfd) != -1);
                        }
 
                        unsetenv(LAUNCHD_TRUSTED_FD_ENV);
                        }
 
                        unsetenv(LAUNCHD_TRUSTED_FD_ENV);
@@ -5925,14 +6432,25 @@ jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bo
                mxmsgsz = job_mig_protocol_vproc_subsystem.maxsize;
        }
 
                mxmsgsz = job_mig_protocol_vproc_subsystem.maxsize;
        }
 
+       /* Total hacks. But the MIG server loop is too generic, and the more dynamic
+        * parts of it haven't been tested, or if they have, it was a very long time
+        * ago.
+        */
+       if (xpc_events_xpc_events_subsystem.maxsize > mxmsgsz) {
+               mxmsgsz = xpc_events_xpc_events_subsystem.maxsize;
+       }
+       if (xpc_domain_xpc_domain_subsystem.maxsize > mxmsgsz) {
+               mxmsgsz = xpc_domain_xpc_domain_subsystem.maxsize;
+       }
+
        if (!jm) {
        if (!jm) {
-               jobmgr_assumes(jmr, kevent_mod(SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, jmr) != -1);
-               jobmgr_assumes(jmr, kevent_mod(SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, jmr) != -1);
-               jobmgr_assumes(jmr, kevent_mod(SIGUSR2, EVFILT_SIGNAL, EV_ADD, 0, 0, jmr) != -1);
-               jobmgr_assumes(jmr, kevent_mod(0, EVFILT_FS, EV_ADD, VQ_MOUNT|VQ_UNMOUNT|VQ_UPDATE, 0, jmr) != -1);
+               (void)jobmgr_assumes(jmr, kevent_mod(SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, jmr) != -1);
+               (void)jobmgr_assumes(jmr, kevent_mod(SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, jmr) != -1);
+               (void)jobmgr_assumes(jmr, kevent_mod(SIGUSR2, EVFILT_SIGNAL, EV_ADD, 0, 0, jmr) != -1);
+               (void)jobmgr_assumes(jmr, kevent_mod(0, EVFILT_FS, EV_ADD, VQ_MOUNT|VQ_UNMOUNT|VQ_UPDATE, 0, jmr) != -1);
        }
 
        }
 
-       if (name && !no_init) {
+       if (name && !skip_init) {
                bootstrapper = jobmgr_init_session(jmr, name, sflag);
        }
 
                bootstrapper = jobmgr_init_session(jmr, name, sflag);
        }
 
@@ -5942,18 +6460,19 @@ jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bo
                }
        }
 
                }
        }
 
-       STAILQ_INIT(&jmr->pending_samples);
-
        jobmgr_log(jmr, LOG_DEBUG, "Created job manager%s%s", jm ? " with parent: " : ".", jm ? jm->name : "");
 
        if (bootstrapper) {
        jobmgr_log(jmr, LOG_DEBUG, "Created job manager%s%s", jm ? " with parent: " : ".", jm ? jm->name : "");
 
        if (bootstrapper) {
-               bootstrapper->audit_session = session_port;
-               if( session_port != MACH_PORT_NULL ) {
-                       mach_port_mod_refs(mach_task_self(), session_port, MACH_PORT_RIGHT_SEND, 1);
-               }
+               bootstrapper->asport = asport;
                
                
-               jobmgr_log(jmr, LOG_DEBUG, "Bootstrapping new job manager with audit session %u", session_port);
-               jobmgr_assumes(jmr, job_dispatch(bootstrapper, true) != NULL);
+               jobmgr_log(jmr, LOG_DEBUG, "Bootstrapping new job manager with audit session %u", asport);
+               (void)jobmgr_assumes(jmr, job_dispatch(bootstrapper, true) != NULL);
+       } else {
+               jmr->req_asport = asport;
+       }
+
+       if (asport != MACH_PORT_NULL) {
+               (void)jobmgr_assumes(jmr, launchd_mport_copy_send(asport) == KERN_SUCCESS);
        }
 
        if (jmr->parentmgr) {
        }
 
        if (jmr->parentmgr) {
@@ -5965,10 +6484,102 @@ jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bo
 out_bad:
        if (jmr) {
                jobmgr_remove(jmr);
 out_bad:
        if (jmr) {
                jobmgr_remove(jmr);
+               if (jm == NULL) {
+                       root_jobmgr = NULL;
+               }
        }
        return NULL;
 }
 
        }
        return NULL;
 }
 
+#ifndef __LAUNCH_DISABLE_XPC_SUPPORT__
+jobmgr_t
+jobmgr_new_xpc_singleton_domain(jobmgr_t jm, name_t name)
+{
+       jobmgr_t new = NULL;
+
+       /* These job managers are basically singletons, so we use the root Mach
+        * bootstrap port as their requestor ports so they'll never go away.
+        */
+       mach_port_t req_port = root_jobmgr->jm_port;
+       if (jobmgr_assumes(jm, launchd_mport_make_send(req_port) == KERN_SUCCESS)) {
+               new = jobmgr_new(root_jobmgr, req_port, MACH_PORT_NULL, false, name, true, MACH_PORT_NULL);
+               if (new) {
+                       new->properties |= BOOTSTRAP_PROPERTY_XPC_SINGLETON;
+                       new->properties |= BOOTSTRAP_PROPERTY_XPC_DOMAIN;
+                       new->xpc_singleton = true;
+               }
+       }
+
+       return new;
+}
+
+jobmgr_t
+jobmgr_find_xpc_per_user_domain(jobmgr_t jm, uid_t uid)
+{
+       jobmgr_t jmi = NULL;
+       LIST_FOREACH(jmi, &_s_xpc_user_domains, xpc_le) {
+               if (jmi->req_euid == uid) {
+                       return jmi;
+               }
+       }
+
+       name_t name;
+       (void)snprintf(name, sizeof(name), "com.apple.xpc.domain.peruser.%u", uid);
+       jmi = jobmgr_new_xpc_singleton_domain(jm, name);
+       if (jobmgr_assumes(jm, jmi != NULL)) {
+               /* We need to create a per-user launchd for this UID if there isn't one
+                * already so we can grab the bootstrap port.
+                */
+               job_t puj = jobmgr_lookup_per_user_context_internal(NULL, uid, &jmi->req_bsport);
+               if (jobmgr_assumes(jmi, puj != NULL)) {
+                       (void)jobmgr_assumes(jmi, launchd_mport_copy_send(puj->asport) == KERN_SUCCESS);
+                       (void)jobmgr_assumes(jmi, launchd_mport_copy_send(jmi->req_bsport) == KERN_SUCCESS);
+                       jmi->shortdesc = "per-user";
+                       jmi->req_asport = puj->asport;
+                       jmi->req_asid = puj->asid;
+                       jmi->req_euid = uid;
+                       jmi->req_egid = -1;
+
+                       LIST_INSERT_HEAD(&_s_xpc_user_domains, jmi, xpc_le);
+               } else {
+                       jobmgr_remove(jmi);
+               }
+       }
+
+       return jmi;
+}
+
+jobmgr_t
+jobmgr_find_xpc_per_session_domain(jobmgr_t jm, au_asid_t asid)
+{
+       jobmgr_t jmi = NULL;
+       LIST_FOREACH(jmi, &_s_xpc_session_domains, xpc_le) {
+               if (jmi->req_asid == asid) {
+                       return jmi;
+               }
+       }
+
+       name_t name;
+       (void)snprintf(name, sizeof(name), "com.apple.xpc.domain.persession.%i", asid);
+       jmi = jobmgr_new_xpc_singleton_domain(jm, name);
+       if (jobmgr_assumes(jm, jmi != NULL)) {
+               (void)jobmgr_assumes(jmi, launchd_mport_make_send(root_jobmgr->jm_port) == KERN_SUCCESS);
+               jmi->shortdesc = "per-session";
+               jmi->req_bsport = root_jobmgr->jm_port;
+               (void)jobmgr_assumes(jmi, audit_session_port(asid, &jmi->req_asport) == 0);
+               jmi->req_asid = asid;
+               jmi->req_euid = -1;
+               jmi->req_egid = -1;
+
+               LIST_INSERT_HEAD(&_s_xpc_session_domains, jmi, xpc_le);
+       } else {
+               jobmgr_remove(jmi);
+       }
+
+       return jmi;
+}
+#endif
+
 job_t
 jobmgr_init_session(jobmgr_t jm, const char *session_type, bool sflag)
 {
 job_t
 jobmgr_init_session(jobmgr_t jm, const char *session_type, bool sflag)
 {
@@ -5979,7 +6590,7 @@ jobmgr_init_session(jobmgr_t jm, const char *session_type, bool sflag)
        snprintf(thelabel, sizeof(thelabel), "com.apple.launchctl.%s", session_type);
        bootstrapper = job_new(jm, thelabel, NULL, bootstrap_tool);
        
        snprintf(thelabel, sizeof(thelabel), "com.apple.launchctl.%s", session_type);
        bootstrapper = job_new(jm, thelabel, NULL, bootstrap_tool);
        
-       if( jobmgr_assumes(jm, bootstrapper != NULL) && (jm->parentmgr || !pid1_magic) ) {
+       if (jobmgr_assumes(jm, bootstrapper != NULL) && (jm->parentmgr || !pid1_magic)) {
                bootstrapper->is_bootstrapper = true;
                char buf[100];
 
                bootstrapper->is_bootstrapper = true;
                char buf[100];
 
@@ -5987,22 +6598,21 @@ jobmgr_init_session(jobmgr_t jm, const char *session_type, bool sflag)
                snprintf(buf, sizeof(buf), "0x%X:0:0", getuid());
                envitem_new(bootstrapper, "__CF_USER_TEXT_ENCODING", buf, false, false);
                bootstrapper->weird_bootstrap = true;
                snprintf(buf, sizeof(buf), "0x%X:0:0", getuid());
                envitem_new(bootstrapper, "__CF_USER_TEXT_ENCODING", buf, false, false);
                bootstrapper->weird_bootstrap = true;
-               jobmgr_assumes(jm, job_setup_machport(bootstrapper));
-       } else if( bootstrapper && strncmp(session_type, VPROCMGR_SESSION_SYSTEM, sizeof(VPROCMGR_SESSION_SYSTEM)) == 0 ) {
+               (void)jobmgr_assumes(jm, job_setup_machport(bootstrapper));
+       } else if (bootstrapper && strncmp(session_type, VPROCMGR_SESSION_SYSTEM, sizeof(VPROCMGR_SESSION_SYSTEM)) == 0) {
                bootstrapper->is_bootstrapper = true;
                bootstrapper->is_bootstrapper = true;
-               if( jobmgr_assumes(jm, pid1_magic) ) {
+               if (jobmgr_assumes(jm, pid1_magic)) {
                        /* Have our system bootstrapper print out to the console. */
                        bootstrapper->stdoutpath = strdup(_PATH_CONSOLE);
                        bootstrapper->stderrpath = strdup(_PATH_CONSOLE);
 
                        /* Have our system bootstrapper print out to the console. */
                        bootstrapper->stdoutpath = strdup(_PATH_CONSOLE);
                        bootstrapper->stderrpath = strdup(_PATH_CONSOLE);
 
-                       if( g_console ) {
-                               jobmgr_assumes(jm, kevent_mod((uintptr_t)fileno(g_console), EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_REVOKE, 0, jm) != -1);
+                       if (g_console) {
+                               (void)jobmgr_assumes(jm, kevent_mod((uintptr_t)fileno(g_console), EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_REVOKE, 0, jm) != -1);
                        }
                }
        }
 
        jm->session_initialized = true;
                        }
                }
        }
 
        jm->session_initialized = true;
-
        return bootstrapper;
 }
 
        return bootstrapper;
 }
 
@@ -6024,7 +6634,7 @@ jobmgr_delete_anything_with_port(jobmgr_t jm, mach_port_t port)
 
        if (jm == root_jobmgr) {
                if (port == inherited_bootstrap_port) {
 
        if (jm == root_jobmgr) {
                if (port == inherited_bootstrap_port) {
-                       jobmgr_assumes(jm, launchd_mport_deallocate(port) == KERN_SUCCESS);
+                       (void)jobmgr_assumes(jm, launchd_mport_deallocate(port) == KERN_SUCCESS);
                        inherited_bootstrap_port = MACH_PORT_NULL;
 
                        return jobmgr_shutdown(jm);
                        inherited_bootstrap_port = MACH_PORT_NULL;
 
                        return jobmgr_shutdown(jm);
@@ -6063,7 +6673,7 @@ jobmgr_lookup_service(jobmgr_t jm, const char *name, bool check_parent, pid_t ta
                 */
                
                /* Start in the given bootstrap. */
                 */
                
                /* Start in the given bootstrap. */
-               if( unlikely((target_j = jobmgr_find_by_pid(jm, target_pid, false)) == NULL) ) {
+               if (unlikely((target_j = jobmgr_find_by_pid(jm, target_pid, false)) == NULL)) {
                        /* If we fail, do a deep traversal. */
                        if (unlikely((target_j = jobmgr_find_by_pid_deep(root_jobmgr, target_pid, true)) == NULL)) {
                                jobmgr_log(jm, LOG_DEBUG, "Didn't find PID %i", target_pid);
                        /* If we fail, do a deep traversal. */
                        if (unlikely((target_j = jobmgr_find_by_pid_deep(root_jobmgr, target_pid, true)) == NULL)) {
                                jobmgr_log(jm, LOG_DEBUG, "Didn't find PID %i", target_pid);
@@ -6081,10 +6691,17 @@ jobmgr_lookup_service(jobmgr_t jm, const char *name, bool check_parent, pid_t ta
                return NULL;
        }
        
                return NULL;
        }
        
-       jobmgr_t jm_to_search = ( g_flat_mach_namespace && !(jm->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) ) ? root_jobmgr : jm;
-       LIST_FOREACH(ms, &jm_to_search->ms_hash[hash_ms(name)], name_hash_sle) {
-               if (!ms->per_pid && strcmp(name, ms->name) == 0) {
-                       return ms;
+       jobmgr_t where2look = jm;
+       /* XPC domains are separate from Mach bootstraps. */
+       if (!(jm->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
+               if (g_flat_mach_namespace && !(jm->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET)) {
+                       where2look = root_jobmgr;
+               }
+       }
+       
+       LIST_FOREACH(ms, &where2look->ms_hash[hash_ms(name)], name_hash_sle) {
+               if (!ms->per_pid && strcmp(name, ms->name) == 0) {
+                       return ms;
                }
        }
 
                }
        }
 
@@ -6131,7 +6748,7 @@ machservice_drain_port(struct machservice *ms)
        bool drain_one = ms->drain_one_on_crash;
        bool drain_all = ms->drain_all_on_crash;
        
        bool drain_one = ms->drain_one_on_crash;
        bool drain_all = ms->drain_all_on_crash;
        
-       if( !job_assumes(ms->job, (drain_one || drain_all) == true) ) {
+       if (!job_assumes(ms->job, (drain_one || drain_all) == true)) {
                return;
        }
 
                return;
        }
 
@@ -6149,43 +6766,54 @@ machservice_drain_port(struct machservice *ms)
                 * port, and it will break things if ReportCrash or SafetyNet start advertising other
                 * Mach services. But for now, it should be okay.
                 */
                 * port, and it will break things if ReportCrash or SafetyNet start advertising other
                 * Mach services. But for now, it should be okay.
                 */
-               if( ms->job->alt_exc_handler || ms->job->internal_exc_handler ) {
+               if (ms->job->alt_exc_handler || ms->job->internal_exc_handler) {
                        mr = launchd_exc_runtime_once(ms->port, sizeof(req_buff), sizeof(rep_buff), req_hdr, rep_hdr, 0);
                } else {
                        mach_msg_options_t options =    MACH_RCV_MSG            |
                                                                                        MACH_RCV_TIMEOUT        ;
 
                        mr = mach_msg((mach_msg_header_t *)req_hdr, options, 0, sizeof(req_buff), ms->port, 0, MACH_PORT_NULL);
                        mr = launchd_exc_runtime_once(ms->port, sizeof(req_buff), sizeof(rep_buff), req_hdr, rep_hdr, 0);
                } else {
                        mach_msg_options_t options =    MACH_RCV_MSG            |
                                                                                        MACH_RCV_TIMEOUT        ;
 
                        mr = mach_msg((mach_msg_header_t *)req_hdr, options, 0, sizeof(req_buff), ms->port, 0, MACH_PORT_NULL);
-                       switch( mr ) {
-                               case MACH_MSG_SUCCESS   :
-                                       mach_msg_destroy((mach_msg_header_t *)req_hdr);
-                                       break;
-                               case MACH_RCV_TIMED_OUT :
-                                       break;
-                               case MACH_RCV_TOO_LARGE :
-                                       runtime_syslog(LOG_WARNING, "Tried to receive message that was larger than %lu bytes", sizeof(req_buff));
-                                       break;
-                               default                                 :
-                                       break;
+                       switch (mr) {
+                       case MACH_MSG_SUCCESS:
+                               mach_msg_destroy((mach_msg_header_t *)req_hdr);
+                               break;
+                       case MACH_RCV_TIMED_OUT:
+                               break;
+                       case MACH_RCV_TOO_LARGE:
+                               runtime_syslog(LOG_WARNING, "Tried to receive message that was larger than %lu bytes", sizeof(req_buff));
+                               break;
+                       default:
+                               break;
                        }
                }
                        }
                }
-       } while( drain_all && mr != MACH_RCV_TIMED_OUT );
+       } while (drain_all && mr != MACH_RCV_TIMED_OUT);
 }
 
 void
 machservice_delete(job_t j, struct machservice *ms, bool port_died)
 {
 }
 
 void
 machservice_delete(job_t j, struct machservice *ms, bool port_died)
 {
+       if (ms->alias) {
+               /* HACK: Egregious code duplication. But dealing with aliases is a
+                * pretty simple affair since they can't and shouldn't have any complex
+                * behaviors associated with them.
+                */
+               LIST_REMOVE(ms, name_hash_sle);
+               SLIST_REMOVE(&j->machservices, ms, machservice, sle);
+               free(ms);
+               return;
+       }
+
        if (unlikely(ms->debug_on_close)) {
                job_log(j, LOG_NOTICE, "About to enter kernel debugger because of Mach port: 0x%x", ms->port);
        if (unlikely(ms->debug_on_close)) {
                job_log(j, LOG_NOTICE, "About to enter kernel debugger because of Mach port: 0x%x", ms->port);
-               job_assumes(j, host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER) == KERN_SUCCESS);
+               (void)job_assumes(j, host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER) == KERN_SUCCESS);
        }
 
        if (ms->recv && job_assumes(j, !machservice_active(ms))) {
                job_log(j, LOG_DEBUG, "Closing receive right for %s", ms->name);
        }
 
        if (ms->recv && job_assumes(j, !machservice_active(ms))) {
                job_log(j, LOG_DEBUG, "Closing receive right for %s", ms->name);
-               job_assumes(j, launchd_mport_close_recv(ms->port) == KERN_SUCCESS);
+               (void)job_assumes(j, launchd_mport_close_recv(ms->port) == KERN_SUCCESS);
        }
 
        }
 
-       job_assumes(j, launchd_mport_deallocate(ms->port) == KERN_SUCCESS);
+       (void)job_assumes(j, launchd_mport_deallocate(ms->port) == KERN_SUCCESS);
 
        if (unlikely(ms->port == the_exception_server)) {
                the_exception_server = 0;
 
        if (unlikely(ms->port == the_exception_server)) {
                the_exception_server = 0;
@@ -6196,9 +6824,11 @@ machservice_delete(job_t j, struct machservice *ms, bool port_died)
        if (ms->special_port_num) {
                SLIST_REMOVE(&special_ports, ms, machservice, special_port_sle);
        }
        if (ms->special_port_num) {
                SLIST_REMOVE(&special_ports, ms, machservice, special_port_sle);
        }
-
        SLIST_REMOVE(&j->machservices, ms, machservice, sle);
        SLIST_REMOVE(&j->machservices, ms, machservice, sle);
-       LIST_REMOVE(ms, name_hash_sle);
+
+       if (!(j->dedicated_instance || ms->event_channel)) {
+               LIST_REMOVE(ms, name_hash_sle);
+       }
        LIST_REMOVE(ms, port_hash_sle);
 
        free(ms);
        LIST_REMOVE(ms, port_hash_sle);
 
        free(ms);
@@ -6216,7 +6846,7 @@ machservice_request_notifications(struct machservice *ms)
                job_checkin(ms->job);
        }
 
                job_checkin(ms->job);
        }
 
-       job_assumes(ms->job, launchd_mport_notify_req(ms->port, which) == KERN_SUCCESS);
+       (void)job_assumes(ms->job, launchd_mport_notify_req(ms->port, which) == KERN_SUCCESS);
 }
 
 #define NELEM(x)       (sizeof(x)/sizeof(x[0]))
 }
 
 #define NELEM(x)       (sizeof(x)/sizeof(x[0]))
@@ -6323,15 +6953,25 @@ job_ack_port_destruction(mach_port_t p)
         * ReceiveRight(N - 1)Returned
         */
        
         * ReceiveRight(N - 1)Returned
         */
        
-       if( ms->drain_one_on_crash || ms->drain_all_on_crash ) {
-               if( j->crashed && j->reaped ) {
+       if (ms->drain_one_on_crash || ms->drain_all_on_crash) {
+               if (j->crashed && j->reaped) {
                        job_log(j, LOG_DEBUG, "Job has crashed. Draining port...");
                        machservice_drain_port(ms);
                        job_log(j, LOG_DEBUG, "Job has crashed. Draining port...");
                        machservice_drain_port(ms);
-               } else if( !(j->crashed || j->reaped) ) {
+               } else if (!(j->crashed || j->reaped)) {
                        job_log(j, LOG_DEBUG, "Job's exit status is still unknown. Deferring drain.");
                }
        }
        
                        job_log(j, LOG_DEBUG, "Job's exit status is still unknown. Deferring drain.");
                }
        }
        
+       /* If we get this notification after the job has been reaped, then we want to ping
+        * the event port to keep things going.
+        */
+       if (ms->event_update_port && !j->p && job_assumes(j, j->event_monitor)) {
+               if (_s_event_update_port == MACH_PORT_NULL) {
+                       (void)job_assumes(j, launchd_mport_make_send_once(ms->port, &_s_event_update_port) == KERN_SUCCESS);
+               }
+               eventsystem_ping();
+       }
+       
        ms->isActive = false;
        if (ms->delete_on_destruction) {
                machservice_delete(j, ms, false);
        ms->isActive = false;
        if (ms->delete_on_destruction) {
                machservice_delete(j, ms, false);
@@ -6351,7 +6991,7 @@ job_ack_no_senders(job_t j)
 {
        j->priv_port_has_senders = false;
 
 {
        j->priv_port_has_senders = false;
 
-       job_assumes(j, launchd_mport_close_recv(j->j_port) == KERN_SUCCESS);
+       (void)job_assumes(j, launchd_mport_close_recv(j->j_port) == KERN_SUCCESS);
        j->j_port = 0;
 
        job_log(j, LOG_DEBUG, "No more senders on privileged Mach bootstrap port");
        j->j_port = 0;
 
        job_log(j, LOG_DEBUG, "No more senders on privileged Mach bootstrap port");
@@ -6382,7 +7022,7 @@ semaphoreitem_new(job_t j, semaphore_reason_t why, const char *what)
 
        SLIST_INSERT_HEAD(&j->semaphores, si, sle);
        
 
        SLIST_INSERT_HEAD(&j->semaphores, si, sle);
        
-       if( (why == OTHER_JOB_ENABLED || why == OTHER_JOB_DISABLED) && !j->nosy ) {
+       if ((why == OTHER_JOB_ENABLED || why == OTHER_JOB_DISABLED) && !j->nosy) {
                job_log(j, LOG_DEBUG, "Job is interested in \"%s\".", what);
                SLIST_INSERT_HEAD(&s_curious_jobs, j, curious_jobs_sle);
                j->nosy = true;
                job_log(j, LOG_DEBUG, "Job is interested in \"%s\".", what);
                SLIST_INSERT_HEAD(&s_curious_jobs, j, curious_jobs_sle);
                j->nosy = true;
@@ -6428,15 +7068,15 @@ semaphoreitem_delete(job_t j, struct semaphoreitem *si)
        SLIST_REMOVE(&j->semaphores, si, semaphoreitem, sle);
 
        if (si->fd != -1) {
        SLIST_REMOVE(&j->semaphores, si, semaphoreitem, sle);
 
        if (si->fd != -1) {
-               job_assumes(j, runtime_close(si->fd) != -1);
+               (void)job_assumes(j, runtime_close(si->fd) != -1);
        }
        
        /* We'll need to rethink this if it ever becomes possible to dynamically add or remove semaphores. */
        }
        
        /* We'll need to rethink this if it ever becomes possible to dynamically add or remove semaphores. */
-       if( (si->why == OTHER_JOB_ENABLED || si->why == OTHER_JOB_DISABLED) && j->nosy ) {
+       if ((si->why == OTHER_JOB_ENABLED || si->why == OTHER_JOB_DISABLED) && j->nosy) {
                j->nosy = false;
                SLIST_REMOVE(&s_curious_jobs, j, job_s, curious_jobs_sle);
        }
                j->nosy = false;
                SLIST_REMOVE(&s_curious_jobs, j, job_s, curious_jobs_sle);
        }
-
+       
        free(si);
 }
 
        free(si);
 }
 
@@ -6467,10 +7107,14 @@ semaphoreitem_setup(launch_data_t obj, const char *key, void *context)
                        why = launch_data_get_bool(obj) ? SUCCESSFUL_EXIT : FAILED_EXIT;
                        semaphoreitem_new(j, why, NULL);
                        j->start_pending = true;
                        why = launch_data_get_bool(obj) ? SUCCESSFUL_EXIT : FAILED_EXIT;
                        semaphoreitem_new(j, why, NULL);
                        j->start_pending = true;
-               } else if( strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE_AFTERINITIALDEMAND) == 0 ) {
+               } else if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE_AFTERINITIALDEMAND) == 0) {
                        j->needs_kickoff = launch_data_get_bool(obj);
                        j->needs_kickoff = launch_data_get_bool(obj);
+               } else if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE_CRASHED) == 0) {
+                       why = launch_data_get_bool(obj) ? CRASHED : DID_NOT_CRASH;
+                       semaphoreitem_new(j, why, NULL);
+                       j->start_pending = true;
                } else {
                } else {
-                       job_assumes(j, false);
+                       (void)job_assumes(j, false);
                }
                break;
        case LAUNCH_DATA_DICTIONARY:
                }
                break;
        case LAUNCH_DATA_DICTIONARY:
@@ -6484,18 +7128,163 @@ semaphoreitem_setup(launch_data_t obj, const char *key, void *context)
                        sdic.why_true = OTHER_JOB_ENABLED;
                        sdic.why_false = OTHER_JOB_DISABLED;
                } else {
                        sdic.why_true = OTHER_JOB_ENABLED;
                        sdic.why_false = OTHER_JOB_DISABLED;
                } else {
-                       job_assumes(j, false);
+                       (void)job_assumes(j, false);
                        break;
                }
 
                launch_data_dict_iterate(obj, semaphoreitem_setup_dict_iter, &sdic);
                break;
        default:
                        break;
                }
 
                launch_data_dict_iterate(obj, semaphoreitem_setup_dict_iter, &sdic);
                break;
        default:
-               job_assumes(j, false);
+               (void)job_assumes(j, false);
                break;
        }
 }
 
                break;
        }
 }
 
+bool
+externalevent_new(job_t j, struct eventsystem *sys, char *evname, launch_data_t event)
+{
+       struct externalevent *ee = (struct externalevent *)calloc(1, sizeof(struct externalevent) + strlen(evname) + 1);
+       if (job_assumes(j, ee != NULL)) {
+               ee->event = launch_data_copy(event);
+               if (job_assumes(j, ee->event != NULL)) {
+                       strcpy(ee->name, evname);
+                       ee->job = j;
+                       ee->id = sys->curid;
+                       ee->sys = sys;
+                       ee->state = false;
+                       ee->wanted_state = true;
+                       sys->curid++;
+                       
+                       LIST_INSERT_HEAD(&j->events, ee, job_le);
+                       LIST_INSERT_HEAD(&sys->events, ee, sys_le);
+                       
+                       job_log(j, LOG_DEBUG, "New event: %s:%s", sys->name, evname);
+               } else {
+                       free(ee);
+                       ee = NULL;
+               }
+       }
+
+       eventsystem_ping();
+       return ee;
+}
+
+void
+externalevent_delete(struct externalevent *ee)
+{
+       launch_data_free(ee->event);
+       LIST_REMOVE(ee, job_le);
+       LIST_REMOVE(ee, sys_le);
+       
+       free(ee);
+
+       eventsystem_ping();
+}
+
+void
+externalevent_setup(launch_data_t obj, const char *key, void *context)
+{
+       struct externalevent_iter_ctx *ctx = (struct externalevent_iter_ctx *)context;
+       (void)job_assumes(ctx->j, externalevent_new(ctx->j, ctx->sys, (char *)key, obj));
+}
+
+struct externalevent *
+externalevent_find(const char *sysname, uint64_t id)
+{
+       struct externalevent *ei = NULL;
+       
+       struct eventsystem *es = eventsystem_find(sysname);
+       if (launchd_assumes(es != NULL)) {
+               LIST_FOREACH(ei, &es->events, sys_le) {
+                       if (ei->id == id) {
+                               break;
+                       }
+               }
+       }
+       
+       return ei;
+}
+
+struct eventsystem *
+eventsystem_new(const char *name)
+{
+       struct eventsystem *es = (struct eventsystem *)calloc(1, sizeof(struct eventsystem) + strlen(name) + 1);
+       if (launchd_assumes(es != NULL)) {
+               strcpy(es->name, name);
+               LIST_INSERT_HEAD(&_s_event_systems, es, global_le);
+       }
+
+       return es;
+}
+
+void
+eventsystem_delete(struct eventsystem *es)
+{
+       struct externalevent *ei = NULL;
+       while ((ei = LIST_FIRST(&es->events))) {
+               externalevent_delete(ei);
+       }
+       
+       LIST_REMOVE(es, global_le);
+       
+       free(es);
+}
+
+void
+eventsystem_setup(launch_data_t obj, const char *key, void *context)
+{
+       job_t j = (job_t)context;
+       if (!job_assumes(j, launch_data_get_type(obj) == LAUNCH_DATA_DICTIONARY)) {
+               return;
+       }
+       
+       struct eventsystem *sys = eventsystem_find(key);
+       if (unlikely(sys == NULL)) {
+               sys = eventsystem_new(key);
+               job_log(j, LOG_DEBUG, "New event system: %s", key);
+       }
+       
+       if (job_assumes(j, sys != NULL)) {
+               struct externalevent_iter_ctx ctx = {
+                       .j = j,
+                       .sys = sys,
+               };
+               launch_data_dict_iterate(obj, externalevent_setup, &ctx);
+               sys->has_updates = true;
+       }
+}
+
+struct eventsystem *
+eventsystem_find(const char *name)
+{
+       struct eventsystem *esi = NULL;
+       LIST_FOREACH(esi, &_s_event_systems, global_le) {
+               if (strcmp(name, esi->name) == 0) {
+                       break;
+               }
+       }
+       
+       return esi;
+}
+
+void
+eventsystem_ping(void)
+{
+       /* We don't wrap this in an assumes() macro because we could potentially
+        * call this function many times before the helper job gets back to us
+        * and gives us another send-once right. So if it's MACH_PORT_NULL, that
+        * means that we've sent a ping, but the helper hasn't yet checked in to
+        * get the new set of notifications.
+        */
+       if (_s_event_update_port != MACH_PORT_NULL) {
+               kern_return_t kr = helper_downcall_ping(_s_event_update_port);
+               if (kr != KERN_SUCCESS) {
+                       runtime_syslog(LOG_NOTICE, "helper_downcall_ping(): kr = 0x%x", kr);
+               }
+               _s_event_update_port = MACH_PORT_NULL;
+       }
+}
+
 void
 jobmgr_dispatch_all_semaphores(jobmgr_t jm)
 {
 void
 jobmgr_dispatch_all_semaphores(jobmgr_t jm)
 {
@@ -6722,11 +7511,11 @@ job_mig_setup_shmem(job_t j, mach_port_t *shmem_port)
                        (memory_object_offset_t)vm_addr, VM_PROT_READ|VM_PROT_WRITE, shmem_port, 0);
 
        if (job_assumes(j, kr == 0)) {
                        (memory_object_offset_t)vm_addr, VM_PROT_READ|VM_PROT_WRITE, shmem_port, 0);
 
        if (job_assumes(j, kr == 0)) {
-               job_assumes(j, size_of_page == size_of_page_orig);
+               (void)job_assumes(j, size_of_page == size_of_page_orig);
        }
 
        /* no need to inherit this in child processes */
        }
 
        /* no need to inherit this in child processes */
-       job_assumes(j, vm_inherit(mach_task_self(), (vm_address_t)j->shmem, size_of_page_orig, VM_INHERIT_NONE) == 0);
+       (void)job_assumes(j, vm_inherit(mach_task_self(), (vm_address_t)j->shmem, size_of_page_orig, VM_INHERIT_NONE) == 0);
 
        return kr;
 }
 
        return kr;
 }
@@ -6792,13 +7581,9 @@ job_mig_send_signal(job_t j, mach_port_t srp, name_t targetlabel, int sig)
                return BOOTSTRAP_NO_MEMORY;
        }
 
                return BOOTSTRAP_NO_MEMORY;
        }
 
-       if( unlikely(ldc->euid != 0 && ldc->euid != getuid()) || j->deny_job_creation ) {
-
-       }
-
-       if( unlikely(ldc->euid != 0 && ldc->euid != getuid()) || j->deny_job_creation ) {
+       if (unlikely(ldc->euid != 0 && ldc->euid != getuid()) || j->deny_job_creation) {
        #if TARGET_OS_EMBEDDED  
        #if TARGET_OS_EMBEDDED  
-               if( !j->embedded_special_privileges ) {
+               if (!j->embedded_special_privileges) {
                        return BOOTSTRAP_NOT_PRIVILEGED;
                }
        #else
                        return BOOTSTRAP_NOT_PRIVILEGED;
                }
        #else
@@ -6812,12 +7597,12 @@ job_mig_send_signal(job_t j, mach_port_t srp, name_t targetlabel, int sig)
        }
 #endif
        
        }
 #endif
        
-       if (unlikely(!(otherj = job_find(targetlabel)))) {
+       if (unlikely(!(otherj = job_find(NULL, targetlabel)))) {
                return BOOTSTRAP_UNKNOWN_SERVICE;
        }
 
 #if TARGET_OS_EMBEDDED
                return BOOTSTRAP_UNKNOWN_SERVICE;
        }
 
 #if TARGET_OS_EMBEDDED
-       if( j->embedded_special_privileges && strcmp(j->username, otherj->username) != 0 ) {
+       if (j->embedded_special_privileges && strcmp(j->username, otherj->username) != 0) {
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
 #endif 
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
 #endif 
@@ -6834,7 +7619,7 @@ job_mig_send_signal(job_t j, mach_port_t srp, name_t targetlabel, int sig)
                if (do_block) {
                        job_log(j, LOG_DEBUG, "Blocking MIG return of job_remove(): %s", otherj->label);
                        /* this is messy. We shouldn't access 'otherj' after job_remove(), but we check otherj->p first... */
                if (do_block) {
                        job_log(j, LOG_DEBUG, "Blocking MIG return of job_remove(): %s", otherj->label);
                        /* this is messy. We shouldn't access 'otherj' after job_remove(), but we check otherj->p first... */
-                       job_assumes(otherj, waiting4removal_new(otherj, srp));
+                       (void)job_assumes(otherj, waiting4removal_new(otherj, srp));
                        return MIG_NO_REPLY;
                } else {
                        return 0;
                        return MIG_NO_REPLY;
                } else {
                        return 0;
@@ -6846,20 +7631,21 @@ job_mig_send_signal(job_t j, mach_port_t srp, name_t targetlabel, int sig)
 
                if (!j->shmem) {
                        j->sent_kill_via_shmem = true;
 
                if (!j->shmem) {
                        j->sent_kill_via_shmem = true;
-                       job_assumes(j, runtime_kill(otherj->p, SIGKILL) != -1);
+                       (void)job_assumes(j, runtime_kill(otherj->p, SIGKILL) != -1);
                        return 0;
                }
                        return 0;
                }
-       #if !TARGET_OS_EMBEDDED
+
+#if !TARGET_OS_EMBEDDED
                if (__sync_bool_compare_and_swap(&j->shmem->vp_shmem_transaction_cnt, 0, -1)) {
                        j->shmem->vp_shmem_flags |= VPROC_SHMEM_EXITING;
                        j->sent_kill_via_shmem = true;
                if (__sync_bool_compare_and_swap(&j->shmem->vp_shmem_transaction_cnt, 0, -1)) {
                        j->shmem->vp_shmem_flags |= VPROC_SHMEM_EXITING;
                        j->sent_kill_via_shmem = true;
-                       job_assumes(j, runtime_kill(otherj->p, SIGKILL) != -1);
+                       (void)job_assumes(j, runtime_kill(otherj->p, SIGKILL) != -1);
                        return 0;
                }
                        return 0;
                }
-       #endif
+#endif
                return BOOTSTRAP_NOT_PRIVILEGED;
        } else if (otherj->p) {
                return BOOTSTRAP_NOT_PRIVILEGED;
        } else if (otherj->p) {
-               job_assumes(j, runtime_kill(otherj->p, sig) != -1);
+               (void)job_assumes(j, runtime_kill(otherj->p, sig) != -1);
        }
 
        return 0;
        }
 
        return 0;
@@ -6898,9 +7684,7 @@ job_mig_log_drain(job_t j, mach_port_t srp, vm_offset_t *outval, mach_msg_type_n
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_swap_complex(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey,
-                                        vm_offset_t inval,                             mach_msg_type_number_t invalCnt,
-                                        vm_offset_t *outval,                   mach_msg_type_number_t *outvalCnt)
+job_mig_swap_complex(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey, vm_offset_t inval, mach_msg_type_number_t invalCnt, vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
 {
        const char *action;
        launch_data_t input_obj = NULL, output_obj = NULL;
 {
        const char *action;
        launch_data_t input_obj = NULL, output_obj = NULL;
@@ -6911,11 +7695,9 @@ job_mig_swap_complex(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey,
        if (!launchd_assumes(j != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
        if (!launchd_assumes(j != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
-
        if (unlikely(inkey && ldc->euid && ldc->euid != getuid())) {
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
        if (unlikely(inkey && ldc->euid && ldc->euid != getuid())) {
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
-
        if (unlikely(inkey && outkey && !job_assumes(j, inkey == outkey))) {
                return 1;
        }
        if (unlikely(inkey && outkey && !job_assumes(j, inkey == outkey))) {
                return 1;
        }
@@ -6936,6 +7718,9 @@ job_mig_swap_complex(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey,
                return 1;
        }
 
                return 1;
        }
 
+       /* Note to future maintainers: launch_data_unpack() does NOT return a heap object. The data
+        * is decoded in-place. So do not call launch_data_free() on input_obj.
+        */
        runtime_ktrace0(RTKT_LAUNCHD_DATA_UNPACK);
        if (unlikely(invalCnt && !job_assumes(j, (input_obj = launch_data_unpack((void *)inval, invalCnt, NULL, 0, &data_offset, NULL)) != NULL))) {
                goto out_bad;
        runtime_ktrace0(RTKT_LAUNCHD_DATA_UNPACK);
        if (unlikely(invalCnt && !job_assumes(j, (input_obj = launch_data_unpack((void *)inval, invalCnt, NULL, 0, &data_offset, NULL)) != NULL))) {
                goto out_bad;
@@ -6966,18 +7751,18 @@ job_mig_swap_complex(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey,
                launch_data_free(output_obj);
                break;
        case VPROC_GSK_MGR_NAME:
                launch_data_free(output_obj);
                break;
        case VPROC_GSK_MGR_NAME:
-               if( !job_assumes(j, (output_obj = launch_data_new_string(j->mgr->name)) != NULL) ) {
+               if (!job_assumes(j, (output_obj = launch_data_new_string(j->mgr->name)) != NULL)) {
                        goto out_bad;
                }
                packed_size = launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL);
                if (!job_assumes(j, packed_size != 0)) {
                        goto out_bad;
                }
                        goto out_bad;
                }
                packed_size = launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL);
                if (!job_assumes(j, packed_size != 0)) {
                        goto out_bad;
                }
-                       
+               
                launch_data_free(output_obj);
                break;
        case VPROC_GSK_JOB_OVERRIDES_DB:
                launch_data_free(output_obj);
                break;
        case VPROC_GSK_JOB_OVERRIDES_DB:
-               if( !job_assumes(j, (output_obj = launch_data_new_string(launchd_data_base_path(LAUNCHD_DB_TYPE_OVERRIDES))) != NULL) ) {
+               if (!job_assumes(j, (output_obj = launch_data_new_string(launchd_data_base_path(LAUNCHD_DB_TYPE_OVERRIDES))) != NULL)) {
                        goto out_bad;
                }
                packed_size = launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL);
                        goto out_bad;
                }
                packed_size = launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL);
@@ -6988,7 +7773,7 @@ job_mig_swap_complex(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey,
                launch_data_free(output_obj);
                break;
        case VPROC_GSK_JOB_CACHE_DB:
                launch_data_free(output_obj);
                break;
        case VPROC_GSK_JOB_CACHE_DB:
-               if( !job_assumes(j, (output_obj = launch_data_new_string(launchd_data_base_path(LAUNCHD_DB_TYPE_JOBCACHE))) != NULL) ) {
+               if (!job_assumes(j, (output_obj = launch_data_new_string(launchd_data_base_path(LAUNCHD_DB_TYPE_JOBCACHE))) != NULL)) {
                        goto out_bad;
                }
                packed_size = launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL);
                        goto out_bad;
                }
                packed_size = launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL);
@@ -6997,7 +7782,7 @@ job_mig_swap_complex(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey,
                }
                
                job_log(j, LOG_DEBUG, "Location of job cache database: %s", launch_data_get_string(output_obj));
                }
                
                job_log(j, LOG_DEBUG, "Location of job cache database: %s", launch_data_get_string(output_obj));
-                       
+               
                launch_data_free(output_obj);
                break;
        case 0:
                launch_data_free(output_obj);
                break;
        case 0:
@@ -7010,28 +7795,32 @@ job_mig_swap_complex(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey,
        }
 
        if (invalCnt) switch (inkey) {
        }
 
        if (invalCnt) switch (inkey) {
-       case VPROC_GSK_ENVIRONMENT:     
-               if( launch_data_get_type(input_obj) == LAUNCH_DATA_DICTIONARY ) {
-                       if( j->p ) {
-                               job_log(j, LOG_INFO, "Setting environment for a currently active job. This environment will take effect on the next invocation of the job.");
+               case VPROC_GSK_ENVIRONMENT:     
+                       if (launch_data_get_type(input_obj) == LAUNCH_DATA_DICTIONARY) {
+                               if (j->p) {
+                                       job_log(j, LOG_INFO, "Setting environment for a currently active job. This environment will take effect on the next invocation of the job.");
+                               }
+                               launch_data_dict_iterate(input_obj, envitem_setup_one_shot, j);
                        }
                        }
-                       launch_data_dict_iterate(input_obj, envitem_setup_one_shot, j);
-               }
-               break;
-       case 0:
-               break;
-       default:
-               goto out_bad;
+                       break;
+               case 0:
+                       break;
+               default:
+                       goto out_bad;
        }
        }
-
+       
        mig_deallocate(inval, invalCnt);
        mig_deallocate(inval, invalCnt);
-
        return 0;
        return 0;
-
+       
 out_bad:
 out_bad:
+       mig_deallocate(inval, invalCnt);
        if (*outval) {
                mig_deallocate(*outval, *outvalCnt);
        }
        if (*outval) {
                mig_deallocate(*outval, *outvalCnt);
        }
+       if (output_obj) {
+               launch_data_free(output_obj);
+       }
+       
        return 1;
 }
 
        return 1;
 }
 
@@ -7140,9 +7929,9 @@ job_mig_swap_integer(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey, int64_t inv
                                runtime_add_weak_ref();
                        }
                        j->start_interval = (typeof(j->start_interval)) inval;
                                runtime_add_weak_ref();
                        }
                        j->start_interval = (typeof(j->start_interval)) inval;
-                       job_assumes(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, j->start_interval, j) != -1);
+                       (void)job_assumes(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, j->start_interval, j) != -1);
                } else if (j->start_interval) {
                } else if (j->start_interval) {
-                       job_assumes(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_DELETE, 0, 0, NULL) != -1);
+                       (void)job_assumes(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_DELETE, 0, 0, NULL) != -1);
                        if (j->start_interval != 0) {
                                runtime_del_weak_ref();
                        }
                        if (j->start_interval != 0) {
                                runtime_del_weak_ref();
                        }
@@ -7175,21 +7964,25 @@ job_mig_swap_integer(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey, int64_t inv
                if (inval < 0 || inval > UINT16_MAX) {
                        kr = 1;
                } else {
                if (inval < 0 || inval > UINT16_MAX) {
                        kr = 1;
                } else {
-                       umask((mode_t) inval);
+#if HAVE_SANDBOX
+                       if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
+                               kr = 1;
+                       } else {
+                               umask((mode_t) inval);
+                       }
+#endif
                }
                break;
        case VPROC_GSK_TRANSACTIONS_ENABLED:
                }
                break;
        case VPROC_GSK_TRANSACTIONS_ENABLED:
-               if( !job_assumes(j, inval != 0) ) {
+               if (!job_assumes(j, inval != 0)) {
                        job_log(j, LOG_WARNING, "Attempt to unregister from transaction model. This is not supported.");
                        kr = 1;
                } else {
                        job_log(j, LOG_WARNING, "Attempt to unregister from transaction model. This is not supported.");
                        kr = 1;
                } else {
-                       job_log(j, LOG_DEBUG, "Now participating in transaction model.");
                        j->kill_via_shmem = (bool)inval;
                        j->kill_via_shmem = (bool)inval;
-                       job_log(j, LOG_DEBUG, "j->kill_via_shmem = %s", j->kill_via_shmem ? "true" : "false");
                }
                break;
        case VPROC_GSK_WEIRD_BOOTSTRAP:
                }
                break;
        case VPROC_GSK_WEIRD_BOOTSTRAP:
-               if( job_assumes(j, j->weird_bootstrap) ) {
+               if (job_assumes(j, j->weird_bootstrap)) {
                        job_log(j, LOG_DEBUG, "Unsetting weird bootstrap.");
                        
                        mach_msg_size_t mxmsgsz = (typeof(mxmsgsz)) sizeof(union __RequestUnion__job_mig_protocol_vproc_subsystem);
                        job_log(j, LOG_DEBUG, "Unsetting weird bootstrap.");
                        
                        mach_msg_size_t mxmsgsz = (typeof(mxmsgsz)) sizeof(union __RequestUnion__job_mig_protocol_vproc_subsystem);
@@ -7198,7 +7991,7 @@ job_mig_swap_integer(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey, int64_t inv
                                mxmsgsz = job_mig_protocol_vproc_subsystem.maxsize;
                        }
                        
                                mxmsgsz = job_mig_protocol_vproc_subsystem.maxsize;
                        }
                        
-                       job_assumes(j, runtime_add_mport(j->mgr->jm_port, protocol_vproc_server, mxmsgsz) == KERN_SUCCESS);
+                       (void)job_assumes(j, runtime_add_mport(j->mgr->jm_port, protocol_vproc_server, mxmsgsz) == KERN_SUCCESS);
                        j->weird_bootstrap = false;
                }
                break;
                        j->weird_bootstrap = false;
                }
                break;
@@ -7206,26 +7999,35 @@ job_mig_swap_integer(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey, int64_t inv
                j->wait4debugger_oneshot = inval;
                break;
        case VPROC_GSK_PERUSER_SUSPEND:
                j->wait4debugger_oneshot = inval;
                break;
        case VPROC_GSK_PERUSER_SUSPEND:
-               if( job_assumes(j, pid1_magic && ldc->euid == 0) ) {
+               if (job_assumes(j, pid1_magic && ldc->euid == 0)) {
                        mach_port_t junk = MACH_PORT_NULL;
                        mach_port_t junk = MACH_PORT_NULL;
-                       job_t jpu = jobmgr_lookup_per_user_context_internal(j, (uid_t)inval, false, &junk);
-                       if( job_assumes(j, jpu != NULL) ) {
+                       job_t jpu = jobmgr_lookup_per_user_context_internal(j, (uid_t)inval, &junk);
+                       if (job_assumes(j, jpu != NULL)) {
                                struct suspended_peruser *spi = NULL;
                                struct suspended_peruser *spi = NULL;
-                               LIST_FOREACH( spi, &j->suspended_perusers, sle ) {
-                                       if( (int64_t)(spi->j->mach_uid) == inval ) {
+                               LIST_FOREACH(spi, &j->suspended_perusers, sle) {
+                                       if ((int64_t)(spi->j->mach_uid) == inval) {
                                                job_log(j, LOG_WARNING, "Job tried to suspend per-user launchd for UID %lli twice.", inval);
                                                break;
                                        }
                                }
 
                                                job_log(j, LOG_WARNING, "Job tried to suspend per-user launchd for UID %lli twice.", inval);
                                                break;
                                        }
                                }
 
-                               if( spi == NULL ) {
+                               if (spi == NULL) {
                                        job_log(j, LOG_INFO, "Job is suspending the per-user launchd for UID %lli.", inval);
                                        spi = (struct suspended_peruser *)calloc(sizeof(struct suspended_peruser), 1);
                                        job_log(j, LOG_INFO, "Job is suspending the per-user launchd for UID %lli.", inval);
                                        spi = (struct suspended_peruser *)calloc(sizeof(struct suspended_peruser), 1);
-                                       if( job_assumes(j, spi != NULL) ) {
+                                       if (job_assumes(j, spi != NULL)) {
+                                               /* Stop listening for events.
+                                                *
+                                                * See <rdar://problem/9014146>.
+                                                */
+                                               if (jpu->peruser_suspend_count == 0) {
+                                                       job_ignore(jpu);
+                                               }
+
                                                spi->j = jpu;
                                                spi->j->peruser_suspend_count++;
                                                LIST_INSERT_HEAD(&j->suspended_perusers, spi, sle);
                                                job_stop(spi->j);
                                                spi->j = jpu;
                                                spi->j->peruser_suspend_count++;
                                                LIST_INSERT_HEAD(&j->suspended_perusers, spi, sle);
                                                job_stop(spi->j);
+                                               *outval = jpu->p;
                                        } else {
                                                kr = BOOTSTRAP_NO_MEMORY;
                                        }
                                        } else {
                                                kr = BOOTSTRAP_NO_MEMORY;
                                        }
@@ -7236,10 +8038,10 @@ job_mig_swap_integer(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey, int64_t inv
                }
                break;
        case VPROC_GSK_PERUSER_RESUME:
                }
                break;
        case VPROC_GSK_PERUSER_RESUME:
-               if( job_assumes(j, pid1_magic == true) ) {
+               if (job_assumes(j, pid1_magic == true)) {
                        struct suspended_peruser *spi = NULL, *spt = NULL;
                        struct suspended_peruser *spi = NULL, *spt = NULL;
-                       LIST_FOREACH_SAFE( spi, &j->suspended_perusers, sle, spt ) {
-                               if( (int64_t)(spi->j->mach_uid) == inval ) {
+                       LIST_FOREACH_SAFE(spi, &j->suspended_perusers, sle, spt) {
+                               if ((int64_t)(spi->j->mach_uid) == inval) {
                                        spi->j->peruser_suspend_count--;
                                        LIST_REMOVE(spi, sle);
                                        job_log(j, LOG_INFO, "Job is resuming the per-user launchd for UID %lli.", inval);
                                        spi->j->peruser_suspend_count--;
                                        LIST_REMOVE(spi, sle);
                                        job_log(j, LOG_INFO, "Job is resuming the per-user launchd for UID %lli.", inval);
@@ -7247,10 +8049,11 @@ job_mig_swap_integer(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey, int64_t inv
                                }
                        }
                        
                                }
                        }
                        
-                       if( !job_assumes(j, spi != NULL) ) {
+                       if (!job_assumes(j, spi != NULL)) {
                                job_log(j, LOG_WARNING, "Job tried to resume per-user launchd for UID %lli that it did not suspend.", inval);
                                kr = BOOTSTRAP_NOT_PRIVILEGED;
                                job_log(j, LOG_WARNING, "Job tried to resume per-user launchd for UID %lli that it did not suspend.", inval);
                                kr = BOOTSTRAP_NOT_PRIVILEGED;
-                       } else if( spi->j->peruser_suspend_count == 0 ) {
+                       } else if (spi->j->peruser_suspend_count == 0) {
+                               job_watch(spi->j);
                                job_dispatch(spi->j, false);
                                free(spi);
                        }
                                job_dispatch(spi->j, false);
                                free(spi);
                        }
@@ -7269,7 +8072,7 @@ job_mig_swap_integer(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey, int64_t inv
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_post_fork_ping(job_t j, task_t child_task, mach_port_t *audit_session)
+job_mig_post_fork_ping(job_t j, task_t child_task, mach_port_t *asport)
 {
        struct machservice *ms;
 
 {
        struct machservice *ms;
 
@@ -7306,15 +8109,22 @@ job_mig_post_fork_ping(job_t j, task_t child_task, mach_port_t *audit_session)
                }
        }
 
                }
        }
 
-       mach_port_t _session = MACH_PORT_NULL;
+       /* MIG will not zero-initialize this pointer, so we must always do so. See
+        * <rdar://problem/8562593>.
+        */
+       *asport = MACH_PORT_NULL;
 #if !TARGET_OS_EMBEDDED
 #if !TARGET_OS_EMBEDDED
-       if( !j->anonymous && !j->per_user ) {
-               job_log(j, LOG_DEBUG, "Returning session port %u", j->audit_session);
-               _session = j->audit_session;
+       if (!j->anonymous) {
+               /* XPC services will spawn into the root security session by default.
+                * xpcproxy will switch them away if needed.
+                */
+               if (!(j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
+                       job_log(j, LOG_DEBUG, "Returning j->asport: %u", j->asport);
+                       *asport = j->asport;
+               }
        }
        }
-#endif 
-       *audit_session = _session;
-       job_assumes(j, launchd_mport_deallocate(child_task) == KERN_SUCCESS);
+#endif
+       (void)job_assumes(j, launchd_mport_deallocate(child_task) == KERN_SUCCESS);
 
        return 0;
 }
 
        return 0;
 }
@@ -7323,7 +8133,7 @@ kern_return_t
 job_mig_reboot2(job_t j, uint64_t flags)
 {
        char who_started_the_reboot[2048] = "";
 job_mig_reboot2(job_t j, uint64_t flags)
 {
        char who_started_the_reboot[2048] = "";
-       struct kinfo_proc kp;
+       struct proc_bsdshortinfo proc;
        struct ldcred *ldc = runtime_get_caller_creds();
        pid_t pid_to_log;
 
        struct ldcred *ldc = runtime_get_caller_creds();
        pid_t pid_to_log;
 
@@ -7338,35 +8148,34 @@ job_mig_reboot2(job_t j, uint64_t flags)
 #if !TARGET_OS_EMBEDDED
        if (unlikely(ldc->euid)) {
 #else
 #if !TARGET_OS_EMBEDDED
        if (unlikely(ldc->euid)) {
 #else
-       if( unlikely(ldc->euid) && !j->embedded_special_privileges ) {
+       if (unlikely(ldc->euid) && !j->embedded_special_privileges) {
 #endif
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
 
 #endif
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
 
-       for (pid_to_log = ldc->pid; pid_to_log; pid_to_log = kp.kp_eproc.e_ppid) {
-               int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid_to_log };
-               size_t who_offset, len = sizeof(kp);
-
-               if (!job_assumes(j, sysctl(mib, 4, &kp, &len, NULL, 0) != -1)) {
+       for (pid_to_log = ldc->pid; pid_to_log; pid_to_log = proc.pbsi_ppid) {
+               size_t who_offset;
+               if (proc_pidinfo(pid_to_log, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
+                       if (errno != ESRCH) {
+                               job_assumes(j, errno == 0);
+                       }
                        return 1;
                }
 
                        return 1;
                }
 
-               if( !job_assumes(j, pid_to_log != kp.kp_eproc.e_ppid) ) {
+               if (!job_assumes(j, pid_to_log != (pid_t)proc.pbsi_ppid)) {
                        job_log(j, LOG_WARNING, "Job which is its own parent started reboot.");
                        job_log(j, LOG_WARNING, "Job which is its own parent started reboot.");
-                       snprintf(who_started_the_reboot, sizeof(who_started_the_reboot), "%s[%u]->%s[%u]->%s[%u]->...", kp.kp_proc.p_comm, pid_to_log, kp.kp_proc.p_comm, pid_to_log, kp.kp_proc.p_comm, pid_to_log);
+                       snprintf(who_started_the_reboot, sizeof(who_started_the_reboot), "%s[%u]->%s[%u]->%s[%u]->...", proc.pbsi_comm, pid_to_log, proc.pbsi_comm, pid_to_log, proc.pbsi_comm, pid_to_log);
                        break;
                }
 
                who_offset = strlen(who_started_the_reboot);
                snprintf(who_started_the_reboot + who_offset, sizeof(who_started_the_reboot) - who_offset,
                        break;
                }
 
                who_offset = strlen(who_started_the_reboot);
                snprintf(who_started_the_reboot + who_offset, sizeof(who_started_the_reboot) - who_offset,
-                               " %s[%u]%s", kp.kp_proc.p_comm, pid_to_log, kp.kp_eproc.e_ppid ? " ->" : "");
+                               " %s[%u]%s", proc.pbsi_comm, pid_to_log, proc.pbsi_ppid ? " ->" : "");
        }
 
        root_jobmgr->reboot_flags = (int)flags;
        }
 
        root_jobmgr->reboot_flags = (int)flags;
-
-       launchd_shutdown();
-
        job_log(j, LOG_DEBUG, "reboot2() initiated by:%s", who_started_the_reboot);
        job_log(j, LOG_DEBUG, "reboot2() initiated by:%s", who_started_the_reboot);
+       launchd_shutdown();
 
        return 0;
 }
 
        return 0;
 }
@@ -7378,9 +8187,16 @@ job_mig_getsocket(job_t j, name_t spr)
                return BOOTSTRAP_NO_MEMORY;
        }
 
                return BOOTSTRAP_NO_MEMORY;
        }
 
-       if( j->deny_job_creation ) {
+       if (j->deny_job_creation) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+
+#if HAVE_SANDBOX
+       struct ldcred *ldc = runtime_get_caller_creds(); 
+       if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
+#endif
 
        ipc_server_init();
 
 
        ipc_server_init();
 
@@ -7410,7 +8226,7 @@ job_mig_log(job_t j, int pri, int err, logmsg_t msg)
 }
 
 job_t
 }
 
 job_t
-jobmgr_lookup_per_user_context_internal(job_t j, uid_t which_user, bool dispatch, mach_port_t *mp)
+jobmgr_lookup_per_user_context_internal(job_t j, uid_t which_user, mach_port_t *mp)
 {
        job_t ji = NULL;
        LIST_FOREACH(ji, &root_jobmgr->jobs, sle) {
 {
        job_t ji = NULL;
        LIST_FOREACH(ji, &root_jobmgr->jobs, sle) {
@@ -7429,7 +8245,7 @@ jobmgr_lookup_per_user_context_internal(job_t j, uid_t which_user, bool dispatch
                break;
        }
        
                break;
        }
        
-       if( unlikely(ji == NULL) ) {
+       if (unlikely(ji == NULL)) {
                struct machservice *ms;
                char lbuf[1024];
                
                struct machservice *ms;
                char lbuf[1024];
                
@@ -7439,39 +8255,60 @@ jobmgr_lookup_per_user_context_internal(job_t j, uid_t which_user, bool dispatch
                
                ji = job_new(root_jobmgr, lbuf, "/sbin/launchd", NULL);
                
                
                ji = job_new(root_jobmgr, lbuf, "/sbin/launchd", NULL);
                
-               if( ji != NULL ) {
+               if (ji != NULL) {
+                       auditinfo_addr_t auinfo = {
+                               .ai_termid = { .at_type = AU_IPv4 },
+                               .ai_auid = which_user,
+                               .ai_asid = AU_ASSIGN_ASID,
+                       };
+
+                       if (setaudit_addr(&auinfo, sizeof(auinfo)) == 0) {
+                               job_log(ji, LOG_DEBUG, "Created new security session for per-user launchd: %u", auinfo.ai_asid);
+                               (void)job_assumes(ji, (ji->asport = audit_session_self()) != MACH_PORT_NULL);
+
+                               /* Kinda lame that we have to do this, but we can't create an
+                                * audit session without joining it.
+                                */
+                               (void)job_assumes(ji, audit_session_join(g_audit_session_port));
+                               ji->asid = auinfo.ai_asid;
+                       } else {
+                               job_log(ji, LOG_WARNING, "Could not set audit session!");
+                               job_remove(ji);
+                               return NULL;
+                       }
+
                        ji->mach_uid = which_user;
                        ji->per_user = true;
                        ji->kill_via_shmem = true;
                        ji->mach_uid = which_user;
                        ji->per_user = true;
                        ji->kill_via_shmem = true;
-                       
+
                        struct stat sb;
                        char pu_db[PATH_MAX];
                        snprintf(pu_db, sizeof(pu_db), LAUNCHD_DB_PREFIX "/%s", lbuf);
                        
                        bool created = false;
                        int err = stat(pu_db, &sb);
                        struct stat sb;
                        char pu_db[PATH_MAX];
                        snprintf(pu_db, sizeof(pu_db), LAUNCHD_DB_PREFIX "/%s", lbuf);
                        
                        bool created = false;
                        int err = stat(pu_db, &sb);
-                       if( (err == -1 && errno == ENOENT) || (err == 0 && !S_ISDIR(sb.st_mode)) ) {
-                               if( err == 0 ) {
+                       if ((err == -1 && errno == ENOENT) || (err == 0 && !S_ISDIR(sb.st_mode))) {
+                               if (err == 0) {
                                        char move_aside[PATH_MAX];
                                        snprintf(move_aside, sizeof(move_aside), LAUNCHD_DB_PREFIX "/%s.movedaside", lbuf);
                                        
                                        char move_aside[PATH_MAX];
                                        snprintf(move_aside, sizeof(move_aside), LAUNCHD_DB_PREFIX "/%s.movedaside", lbuf);
                                        
-                                       job_assumes(ji, rename(pu_db, move_aside) != -1);
+                                       (void)job_assumes(ji, rename(pu_db, move_aside) != -1);
                                }
 
                                }
 
-                               job_assumes(ji, mkdir(pu_db, S_IRWXU) != -1);
-                               job_assumes(ji, chown(pu_db, which_user, 0) != -1);
+                               (void)job_assumes(ji, mkdir(pu_db, S_IRWXU) != -1);
+                               (void)job_assumes(ji, chown(pu_db, which_user, 0) != -1);
                                created = true;
                        }
                        
                                created = true;
                        }
                        
-                       if( !created ) {
-                               if( !job_assumes(ji, sb.st_uid == which_user) ) {
-                                       job_assumes(ji, chown(pu_db, which_user, 0) != -1);
+                       if (!created) {
+                               if (!job_assumes(ji, sb.st_uid == which_user)) {
+                                       (void)job_assumes(ji, chown(pu_db, which_user, 0) != -1);
                                }
                                }
-                               if( !job_assumes(ji, sb.st_gid == 0) ) {
-                                       job_assumes(ji, chown(pu_db, which_user, 0) != -1);
+                               if (!job_assumes(ji, sb.st_gid == 0)) {
+                                       (void)job_assumes(ji, chown(pu_db, which_user, 0) != -1);
                                }
                                }
-                               if( !job_assumes(ji, sb.st_mode == (S_IRWXU | S_IFDIR)) ) {
-                                       job_assumes(ji, chmod(pu_db, S_IRWXU) != -1);
+                               if (!job_assumes(ji, sb.st_mode == (S_IRWXU | S_IFDIR))) {
+                                       (void)job_assumes(ji, chmod(pu_db, S_IRWXU) != -1);
                                }
                        }
                        
                                }
                        }
                        
@@ -7481,8 +8318,8 @@ jobmgr_lookup_per_user_context_internal(job_t j, uid_t which_user, bool dispatch
                        } else {
                                ms->per_user_hack = true;
                                ms->hide = true;
                        } else {
                                ms->per_user_hack = true;
                                ms->hide = true;
-                               
-                               ji = dispatch ? job_dispatch(ji, false) : ji;
+
+                               ji = job_dispatch(ji, false);
                        }
                }
        } else {
                        }
                }
        } else {
@@ -7528,40 +8365,66 @@ job_mig_lookup_per_user_context(job_t j, uid_t which_user, mach_port_t *up_cont)
        
        *up_cont = MACH_PORT_NULL;
        
        
        *up_cont = MACH_PORT_NULL;
        
-       jpu = jobmgr_lookup_per_user_context_internal(j, which_user, true, up_cont);
+       jpu = jobmgr_lookup_per_user_context_internal(j, which_user, up_cont);
        
        return 0;
 }
 
 kern_return_t
        
        return 0;
 }
 
 kern_return_t
-job_mig_check_in2(job_t j, name_t servicename, mach_port_t *serviceportp, uint64_t flags)
+job_mig_check_in2(job_t j, name_t servicename, mach_port_t *serviceportp, uuid_t instance_id, uint64_t flags)
 {
        bool per_pid_service = flags & BOOTSTRAP_PER_PID_SERVICE;
 {
        bool per_pid_service = flags & BOOTSTRAP_PER_PID_SERVICE;
+       bool strict = flags & BOOTSTRAP_STRICT_CHECKIN;
        struct ldcred *ldc = runtime_get_caller_creds();
        struct ldcred *ldc = runtime_get_caller_creds();
-       struct machservice *ms;
+       struct machservice *ms = NULL;
        job_t jo;
 
        if (!launchd_assumes(j != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
 
        job_t jo;
 
        if (!launchd_assumes(j != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
 
-       ms = jobmgr_lookup_service(j->mgr, servicename, false, per_pid_service ? ldc->pid : 0);
-
-       if (ms == NULL) {
-               *serviceportp = MACH_PORT_NULL;
-
-               if (unlikely((ms = machservice_new(j, servicename, serviceportp, per_pid_service)) == NULL)) {
-                       return BOOTSTRAP_NO_MEMORY;
-               }
-               
-               /* Treat this like a legacy job. */
-               if( !j->legacy_mach_job ) {
-                       ms->isActive = true;
-                       ms->recv = false;
+       if (j->dedicated_instance) {
+               struct machservice *msi = NULL;
+               SLIST_FOREACH(msi, &j->machservices, sle) {
+                       if (strncmp(servicename, msi->name, sizeof(name_t) - 1) == 0) {
+                               uuid_copy(instance_id, j->instance_id);
+                               ms = msi;
+                               break;
+                       }
                }
                }
+       } else {
+               ms = jobmgr_lookup_service(j->mgr, servicename, false, per_pid_service ? ldc->pid : 0);
+       }
 
 
-               if (!(j->anonymous || j->legacy_LS_job || j->legacy_mach_job)) {
-                       job_log(j, LOG_SCOLDING, "Please add the following service to the configuration file for this job: %s", servicename);
+       if (strict) {
+               if (likely(ms != NULL)) {
+                       if (ms->job != j) {
+                               return BOOTSTRAP_NOT_PRIVILEGED;
+                       } else if (ms->isActive) {
+                               return BOOTSTRAP_SERVICE_ACTIVE;
+                       }
+               } else {
+                       return BOOTSTRAP_UNKNOWN_SERVICE;
+               }
+       } else if (ms == NULL) {
+               if (job_assumes(j, !j->dedicated_instance)) {
+                       *serviceportp = MACH_PORT_NULL;
+                       
+                       if (unlikely((ms = machservice_new(j, servicename, serviceportp, per_pid_service)) == NULL)) {
+                               return BOOTSTRAP_NO_MEMORY;
+                       }
+                       
+                       /* Treat this like a legacy job. */
+                       if (!j->legacy_mach_job) {
+                               ms->isActive = true;
+                               ms->recv = false;
+                       }
+                       
+                       if (!(j->anonymous || j->legacy_LS_job || j->legacy_mach_job)) {
+                               job_log(j, LOG_SCOLDING, "Please add the following service to the configuration file for this job: %s", servicename);
+                       }
+               } else {
+                       return BOOTSTRAP_UNKNOWN_SERVICE;
                }
        } else {
                if (unlikely((jo = machservice_job(ms)) != j)) {
                }
        } else {
                if (unlikely((jo = machservice_job(ms)) != j)) {
@@ -7652,17 +8515,22 @@ job_mig_register2(job_t j, name_t servicename, mach_port_t serviceport, uint64_t
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_look_up2(job_t j, mach_port_t srp, name_t servicename, mach_port_t *serviceportp, pid_t target_pid, uint64_t flags)
+job_mig_look_up2(job_t j, mach_port_t srp, name_t servicename, mach_port_t *serviceportp, pid_t target_pid, uuid_t instance_id, uint64_t flags)
 {
 {
-       struct machservice *ms;
+       struct machservice *ms = NULL;
        struct ldcred *ldc = runtime_get_caller_creds();
        kern_return_t kr;
        bool per_pid_lookup = flags & BOOTSTRAP_PER_PID_SERVICE;
        struct ldcred *ldc = runtime_get_caller_creds();
        kern_return_t kr;
        bool per_pid_lookup = flags & BOOTSTRAP_PER_PID_SERVICE;
+       bool specific_instance = flags & BOOTSTRAP_SPECIFIC_INSTANCE;
+       bool strict_lookup = flags & BOOTSTRAP_STRICT_LOOKUP;
+       bool privileged = flags & BOOTSTRAP_PRIVILEGED_SERVER;
 
        if (!launchd_assumes(j != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
 
 
        if (!launchd_assumes(j != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
 
+       bool xpc_req = j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN;
+
        /* 5641783 for the embedded hack */
 #if !TARGET_OS_EMBEDDED
        if (unlikely(pid1_magic && j->anonymous && j->mgr->parentmgr == NULL && ldc->uid != 0 && ldc->euid != 0)) {
        /* 5641783 for the embedded hack */
 #if !TARGET_OS_EMBEDDED
        if (unlikely(pid1_magic && j->anonymous && j->mgr->parentmgr == NULL && ldc->uid != 0 && ldc->euid != 0)) {
@@ -7671,7 +8539,10 @@ job_mig_look_up2(job_t j, mach_port_t srp, name_t servicename, mach_port_t *serv
 #endif
 
 #if HAVE_SANDBOX
 #endif
 
 #if HAVE_SANDBOX
-       if (unlikely(sandbox_check(ldc->pid, "mach-lookup", per_pid_lookup ? SANDBOX_FILTER_LOCAL_NAME : SANDBOX_FILTER_GLOBAL_NAME, servicename) > 0)) {
+       /* We don't do sandbox checking for XPC domains because, by definition, all
+        * the services within your domain should be accessibly to you.
+        */
+       if (!xpc_req && unlikely(sandbox_check(ldc->pid, "mach-lookup", per_pid_lookup ? SANDBOX_FILTER_LOCAL_NAME : SANDBOX_FILTER_GLOBAL_NAME, servicename) > 0)) {
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
 #endif
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
 #endif
@@ -7679,19 +8550,81 @@ job_mig_look_up2(job_t j, mach_port_t srp, name_t servicename, mach_port_t *serv
        if (per_pid_lookup) {
                ms = jobmgr_lookup_service(j->mgr, servicename, false, target_pid);
        } else {
        if (per_pid_lookup) {
                ms = jobmgr_lookup_service(j->mgr, servicename, false, target_pid);
        } else {
-               ms = jobmgr_lookup_service(j->mgr, servicename, true, 0);
+               if (xpc_req) {
+                       /* Requests from XPC domains stay local. */
+                       ms = jobmgr_lookup_service(j->mgr, servicename, false, 0);
+               } else {
+                       /* A strict lookup which is privileged won't even bother trying to
+                        * find a service if we're not hosting the root Mach bootstrap.
+                        */
+                       if (strict_lookup && privileged) {
+                               if (inherited_bootstrap_port == MACH_PORT_NULL) {
+                                       ms = jobmgr_lookup_service(j->mgr, servicename, true, 0);
+                               }
+                       } else {
+                               ms = jobmgr_lookup_service(j->mgr, servicename, true, 0);
+                       }
+               }
        }
 
        if (likely(ms)) {
        }
 
        if (likely(ms)) {
-               if (machservice_hidden(ms) && !machservice_active(ms)) {
-                       ms = NULL;
-               } else if (unlikely(ms->per_user_hack)) {
+               ms = ms->alias ? ms->alias : ms;
+               if (unlikely(specific_instance && ms->job->multiple_instances)) {
+                       job_t ji = NULL;
+                       job_t instance = NULL;
+                       LIST_FOREACH(ji, &ms->job->subjobs, subjob_sle) {
+                               if (uuid_compare(instance_id, ji->instance_id) == 0) {
+                                       instance = ji;
+                                       break;
+                               }
+                       }
+
+                       if (unlikely(instance == NULL)) {
+                               job_log(ms->job, LOG_DEBUG, "Creating new instance of job based on lookup of service %s", ms->name);
+                               instance = job_new_subjob(ms->job, instance_id);
+                               if (job_assumes(j, instance != NULL)) {
+                                       /* Disable this support for now. We only support having 
+                                        * multi-instance jobs within private XPC domains.
+                                        */
+#if 0
+                                       /* If the job is multi-instance, in a singleton XPC domain
+                                        * and the request is not coming from within that singleton
+                                        * domain, we need to alias the new job into the requesting
+                                        * domain.
+                                        */
+                                       if (!j->mgr->xpc_singleton && xpc_req) {
+                                               (void)job_assumes(instance, job_new_alias(j->mgr, instance));
+                                       }
+#endif
+                                       job_dispatch(instance, false);
+                               }
+                       }
+                       
                        ms = NULL;
                        ms = NULL;
+                       if (job_assumes(j, instance != NULL)) {
+                               struct machservice *msi = NULL;
+                               SLIST_FOREACH(msi, &instance->machservices, sle) {
+                                       /* sizeof(servicename) will return the size of a pointer, even though it's
+                                        * an array type, because when passing arrays as parameters in C, they
+                                        * implicitly degrade to pointers.
+                                        */
+                                       if (strncmp(servicename, msi->name, sizeof(name_t) - 1) == 0) {
+                                               ms = msi;
+                                               break;
+                                       }
+                               }
+                       }
+               } else {
+                       if (machservice_hidden(ms) && !machservice_active(ms)) {
+                               ms = NULL;
+                       } else if (unlikely(ms->per_user_hack)) {
+                               ms = NULL;
+                       }
                }
        }
 
        if (likely(ms)) {
                }
        }
 
        if (likely(ms)) {
-               job_assumes(j, machservice_port(ms) != MACH_PORT_NULL);
+               (void)job_assumes(j, machservice_port(ms) != MACH_PORT_NULL);
                job_log(j, LOG_DEBUG, "%sMach service lookup: %s", per_pid_lookup ? "Per PID " : "", servicename);
 
                if (unlikely(!per_pid_lookup && j->lastlookup == ms && j->lastlookup_gennum == ms->gen_num && !j->per_user)) {
                job_log(j, LOG_DEBUG, "%sMach service lookup: %s", per_pid_lookup ? "Per PID " : "", servicename);
 
                if (unlikely(!per_pid_lookup && j->lastlookup == ms && j->lastlookup_gennum == ms->gen_num && !j->per_user)) {
@@ -7705,10 +8638,18 @@ job_mig_look_up2(job_t j, mach_port_t srp, name_t servicename, mach_port_t *serv
                *serviceportp = machservice_port(ms);
 
                kr = BOOTSTRAP_SUCCESS;
                *serviceportp = machservice_port(ms);
 
                kr = BOOTSTRAP_SUCCESS;
-       } else if (!per_pid_lookup && (inherited_bootstrap_port != MACH_PORT_NULL)) {
+       } else if (strict_lookup && !privileged) {
+               /* Hack: We need to simulate XPC's desire not to establish a hierarchy. So if
+                * XPC is doing the lookup, and it's not a privileged lookup, we won't forward.
+                * But if it is a privileged lookup (that is, was looked up in XPC_DOMAIN_LOCAL_SYSTEM)
+                * then we must forward.
+                */
+               return BOOTSTRAP_UNKNOWN_SERVICE;
+       } else if (inherited_bootstrap_port != MACH_PORT_NULL) {
+               /* Requests from within an XPC domain don't get forwarded. */
                job_log(j, LOG_DEBUG, "Mach service lookup forwarded: %s", servicename);
                /* Clients potentially check the audit token of the reply to verify that the returned send right is trustworthy. */
                job_log(j, LOG_DEBUG, "Mach service lookup forwarded: %s", servicename);
                /* Clients potentially check the audit token of the reply to verify that the returned send right is trustworthy. */
-               job_assumes(j, vproc_mig_look_up2_forward(inherited_bootstrap_port, srp, servicename, 0, 0) == 0);
+               (void)job_assumes(j, vproc_mig_look_up2_forward(inherited_bootstrap_port, srp, servicename, target_pid, instance_id, flags) == 0);
                /* The previous routine moved the reply port, we're forced to return MIG_NO_REPLY now */
                return MIG_NO_REPLY;
        } else if (pid1_magic && j->anonymous && ldc->euid >= 500 && strcasecmp(j->mgr->name, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
                /* The previous routine moved the reply port, we're forced to return MIG_NO_REPLY now */
                return MIG_NO_REPLY;
        } else if (pid1_magic && j->anonymous && ldc->euid >= 500 && strcasecmp(j->mgr->name, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
@@ -7742,7 +8683,7 @@ job_mig_parent(job_t j, mach_port_t srp, mach_port_t *parentport)
        } else if (MACH_PORT_NULL == inherited_bootstrap_port) {
                *parentport = jm->jm_port;
        } else {
        } else if (MACH_PORT_NULL == inherited_bootstrap_port) {
                *parentport = jm->jm_port;
        } else {
-               job_assumes(j, vproc_mig_parent_forward(inherited_bootstrap_port, srp) == 0);
+               (void)job_assumes(j, vproc_mig_parent_forward(inherited_bootstrap_port, srp) == 0);
                /* The previous routine moved the reply port, we're forced to return MIG_NO_REPLY now */
                return MIG_NO_REPLY;
        }
                /* The previous routine moved the reply port, we're forced to return MIG_NO_REPLY now */
                return MIG_NO_REPLY;
        }
@@ -7750,10 +8691,21 @@ job_mig_parent(job_t j, mach_port_t srp, mach_port_t *parentport)
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_info(job_t j,  name_array_t *servicenamesp, unsigned int *servicenames_cnt,
-                                               name_array_t *servicejobsp, unsigned int *servicejobs_cnt,
-                                               bootstrap_status_array_t *serviceactivesp, unsigned int *serviceactives_cnt,
-                                               uint64_t flags)
+job_mig_get_root_bootstrap(job_t j, mach_port_t *rootbsp)
+{
+       if (inherited_bootstrap_port == MACH_PORT_NULL) {
+               *rootbsp = root_jobmgr->jm_port;
+               (void)job_assumes(j, launchd_mport_make_send(root_jobmgr->jm_port) == KERN_SUCCESS);
+       } else {
+               *rootbsp = inherited_bootstrap_port;
+               (void)job_assumes(j, launchd_mport_copy_send(inherited_bootstrap_port) == KERN_SUCCESS);
+       }
+
+       return BOOTSTRAP_SUCCESS;
+}
+
+kern_return_t
+job_mig_info(job_t j, name_array_t *servicenamesp, unsigned int *servicenames_cnt, name_array_t *servicejobsp, unsigned int *servicejobs_cnt, bootstrap_status_array_t *serviceactivesp, unsigned int *serviceactives_cnt, uint64_t flags)
 {
        name_array_t service_names = NULL;
        name_array_t service_jobs = NULL;
 {
        name_array_t service_names = NULL;
        name_array_t service_jobs = NULL;
@@ -7765,8 +8717,8 @@ job_mig_info(job_t j,     name_array_t *servicenamesp, unsigned int *servicenames_cn
                return BOOTSTRAP_NO_MEMORY;
        }
 
                return BOOTSTRAP_NO_MEMORY;
        }
 
-       if( g_flat_mach_namespace ) {
-               if( (j->mgr->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) || (flags & BOOTSTRAP_FORCE_LOCAL) ) {
+       if (g_flat_mach_namespace) {
+               if ((j->mgr->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) || (flags & BOOTSTRAP_FORCE_LOCAL)) {
                        jm = j->mgr;
                } else {
                        jm = root_jobmgr;
                        jm = j->mgr;
                } else {
                        jm = root_jobmgr;
@@ -7777,8 +8729,8 @@ job_mig_info(job_t j,     name_array_t *servicenamesp, unsigned int *servicenames_cn
 
        unsigned int i = 0;
        struct machservice *msi = NULL;
 
        unsigned int i = 0;
        struct machservice *msi = NULL;
-       for( i = 0; i < MACHSERVICE_HASH_SIZE; i++ ) {
-               LIST_FOREACH( msi, &jm->ms_hash[i], name_hash_sle ) {
+       for (i = 0; i < MACHSERVICE_HASH_SIZE; i++) {
+               LIST_FOREACH(msi, &jm->ms_hash[i], name_hash_sle) {
                        cnt += !msi->per_pid ? 1 : 0;
                }
        }
                        cnt += !msi->per_pid ? 1 : 0;
                }
        }
@@ -7802,18 +8754,23 @@ job_mig_info(job_t j,   name_array_t *servicenamesp, unsigned int *servicenames_cn
                goto out_bad;
        }
 
                goto out_bad;
        }
 
-       for( i = 0; i < MACHSERVICE_HASH_SIZE; i++ ) {
-               LIST_FOREACH( msi, &jm->ms_hash[i], name_hash_sle ) {
-                       if( !msi->per_pid ) {
+       for (i = 0; i < MACHSERVICE_HASH_SIZE; i++) {
+               LIST_FOREACH(msi, &jm->ms_hash[i], name_hash_sle) {
+                       if (!msi->per_pid) {
                                strlcpy(service_names[cnt2], machservice_name(msi), sizeof(service_names[0]));
                                strlcpy(service_names[cnt2], machservice_name(msi), sizeof(service_names[0]));
-                               strlcpy(service_jobs[cnt2], msi->job->label, sizeof(service_jobs[0]));
+                               msi = msi->alias ? msi->alias : msi;
+                               if (msi->job->mgr->shortdesc) {
+                                       strlcpy(service_jobs[cnt2], msi->job->mgr->shortdesc, sizeof(service_jobs[0]));
+                               } else {
+                                       strlcpy(service_jobs[cnt2], msi->job->label, sizeof(service_jobs[0]));
+                               }
                                service_actives[cnt2] = machservice_status(msi);
                                cnt2++;
                        }
                }
        }
 
                                service_actives[cnt2] = machservice_status(msi);
                                cnt2++;
                        }
                }
        }
 
-       job_assumes(j, cnt == cnt2);
+       (void)job_assumes(j, cnt == cnt2);
 
 out:
        *servicenamesp = service_names;
 
 out:
        *servicenamesp = service_names;
@@ -7838,12 +8795,10 @@ out_bad:
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_lookup_children(job_t j,       mach_port_array_t *child_ports,                                 mach_msg_type_number_t *child_ports_cnt, 
-                                                                       name_array_t *child_names,                                              mach_msg_type_number_t *child_names_cnt, 
-                                                                       bootstrap_property_array_t *child_properties,   mach_msg_type_number_t *child_properties_cnt)
+job_mig_lookup_children(job_t j, mach_port_array_t *child_ports, mach_msg_type_number_t *child_ports_cnt, name_array_t *child_names, mach_msg_type_number_t *child_names_cnt, bootstrap_property_array_t *child_properties,mach_msg_type_number_t *child_properties_cnt)
 {
        kern_return_t kr = BOOTSTRAP_NO_MEMORY;
 {
        kern_return_t kr = BOOTSTRAP_NO_MEMORY;
-       if( !launchd_assumes(j != NULL) ) {
+       if (!launchd_assumes(j != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
        
                return BOOTSTRAP_NO_MEMORY;
        }
        
@@ -7853,7 +8808,7 @@ job_mig_lookup_children(job_t j,  mach_port_array_t *child_ports,                                 mach_msg_ty
         * Otherwise, this could be used to cross sessions, which counts as a security vulnerability
         * in a non-flat namespace.
         */
         * Otherwise, this could be used to cross sessions, which counts as a security vulnerability
         * in a non-flat namespace.
         */
-       if( ldc->euid != 0 ) {
+       if (ldc->euid != 0) {
                job_log(j, LOG_WARNING, "Attempt to look up children of bootstrap by unprivileged job.");
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
                job_log(j, LOG_WARNING, "Attempt to look up children of bootstrap by unprivileged job.");
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
@@ -7862,46 +8817,46 @@ job_mig_lookup_children(job_t j,        mach_port_array_t *child_ports,                                 mach_msg_ty
        
        jobmgr_t jmr = j->mgr;
        jobmgr_t jmi = NULL;
        
        jobmgr_t jmr = j->mgr;
        jobmgr_t jmi = NULL;
-       SLIST_FOREACH( jmi, &jmr->submgrs, sle ) {
+       SLIST_FOREACH(jmi, &jmr->submgrs, sle) {
                cnt++;
        }
        
        /* Find our per-user launchds if we're PID 1. */
        job_t ji = NULL;
                cnt++;
        }
        
        /* Find our per-user launchds if we're PID 1. */
        job_t ji = NULL;
-       if( pid1_magic ) {
-               LIST_FOREACH( ji, &jmr->jobs, sle ) {
+       if (pid1_magic) {
+               LIST_FOREACH(ji, &jmr->jobs, sle) {
                        cnt += ji->per_user ? 1 : 0;
                }
        }
        
                        cnt += ji->per_user ? 1 : 0;
                }
        }
        
-       if( cnt == 0 ) {
+       if (cnt == 0) {
                return BOOTSTRAP_NO_CHILDREN;
        }
        
        mach_port_array_t _child_ports = NULL;
        mig_allocate((vm_address_t *)&_child_ports, cnt * sizeof(_child_ports[0]));
                return BOOTSTRAP_NO_CHILDREN;
        }
        
        mach_port_array_t _child_ports = NULL;
        mig_allocate((vm_address_t *)&_child_ports, cnt * sizeof(_child_ports[0]));
-       if( !job_assumes(j, _child_ports != NULL) ) {
+       if (!job_assumes(j, _child_ports != NULL)) {
                kr = BOOTSTRAP_NO_MEMORY;
                goto out_bad;
        }
        
        name_array_t _child_names = NULL;
        mig_allocate((vm_address_t *)&_child_names, cnt * sizeof(_child_names[0]));
                kr = BOOTSTRAP_NO_MEMORY;
                goto out_bad;
        }
        
        name_array_t _child_names = NULL;
        mig_allocate((vm_address_t *)&_child_names, cnt * sizeof(_child_names[0]));
-       if( !job_assumes(j, _child_names != NULL) ) {
+       if (!job_assumes(j, _child_names != NULL)) {
                kr = BOOTSTRAP_NO_MEMORY;
                goto out_bad;
        }
        
        bootstrap_property_array_t _child_properties = NULL;
        mig_allocate((vm_address_t *)&_child_properties, cnt * sizeof(_child_properties[0]));
                kr = BOOTSTRAP_NO_MEMORY;
                goto out_bad;
        }
        
        bootstrap_property_array_t _child_properties = NULL;
        mig_allocate((vm_address_t *)&_child_properties, cnt * sizeof(_child_properties[0]));
-       if( !job_assumes(j, _child_properties != NULL) ) {
+       if (!job_assumes(j, _child_properties != NULL)) {
                kr = BOOTSTRAP_NO_MEMORY;
                goto out_bad;
        }
        
        unsigned int cnt2 = 0;
                kr = BOOTSTRAP_NO_MEMORY;
                goto out_bad;
        }
        
        unsigned int cnt2 = 0;
-       SLIST_FOREACH( jmi, &jmr->submgrs, sle ) {
-               if( jobmgr_assumes(jmi, launchd_mport_make_send(jmi->jm_port) == KERN_SUCCESS) ) {
+       SLIST_FOREACH(jmi, &jmr->submgrs, sle) {
+               if (jobmgr_assumes(jmi, launchd_mport_make_send(jmi->jm_port) == KERN_SUCCESS)) {
                        _child_ports[cnt2] = jmi->jm_port;
                } else {
                        _child_ports[cnt2] = MACH_PORT_NULL;
                        _child_ports[cnt2] = jmi->jm_port;
                } else {
                        _child_ports[cnt2] = MACH_PORT_NULL;
@@ -7913,12 +8868,12 @@ job_mig_lookup_children(job_t j,        mach_port_array_t *child_ports,                                 mach_msg_ty
                cnt2++;
        }
        
                cnt2++;
        }
        
-       if( pid1_magic ) LIST_FOREACH( ji, &jmr->jobs, sle ) {
-               if( ji->per_user ) {
-                       if( job_assumes(ji, SLIST_FIRST(&ji->machservices)->per_user_hack == true) ) {
+       if (pid1_magic) LIST_FOREACH( ji, &jmr->jobs, sle) {
+               if (ji->per_user) {
+                       if (job_assumes(ji, SLIST_FIRST(&ji->machservices)->per_user_hack == true)) {
                                mach_port_t port = machservice_port(SLIST_FIRST(&ji->machservices));
                                
                                mach_port_t port = machservice_port(SLIST_FIRST(&ji->machservices));
                                
-                               if( job_assumes(ji, launchd_mport_copy_send(port) == KERN_SUCCESS) ) {
+                               if (job_assumes(ji, launchd_mport_copy_send(port) == KERN_SUCCESS)) {
                                        _child_ports[cnt2] = port;
                                } else {
                                        _child_ports[cnt2] = MACH_PORT_NULL;
                                        _child_ports[cnt2] = port;
                                } else {
                                        _child_ports[cnt2] = MACH_PORT_NULL;
@@ -7943,21 +8898,21 @@ job_mig_lookup_children(job_t j,        mach_port_array_t *child_ports,                                 mach_msg_ty
        *child_properties = _child_properties;
        
        unsigned int i = 0;
        *child_properties = _child_properties;
        
        unsigned int i = 0;
-       for( i = 0; i < cnt; i++ ) {
+       for (i = 0; i < cnt; i++) {
                job_log(j, LOG_DEBUG, "child_names[%u] = %s", i, (char *)_child_names[i]);
        }
        
        return BOOTSTRAP_SUCCESS;
 out_bad:
                job_log(j, LOG_DEBUG, "child_names[%u] = %s", i, (char *)_child_names[i]);
        }
        
        return BOOTSTRAP_SUCCESS;
 out_bad:
-       if( _child_ports ) {
+       if (_child_ports) {
                mig_deallocate((vm_address_t)_child_ports, cnt * sizeof(_child_ports[0]));
        }
        
                mig_deallocate((vm_address_t)_child_ports, cnt * sizeof(_child_ports[0]));
        }
        
-       if( _child_names ) {
+       if (_child_names) {
                mig_deallocate((vm_address_t)_child_names, cnt * sizeof(_child_ports[0]));
        }
        
                mig_deallocate((vm_address_t)_child_names, cnt * sizeof(_child_ports[0]));
        }
        
-       if( _child_properties ) {
+       if (_child_properties) {
                mig_deallocate((vm_address_t)_child_properties, cnt * sizeof(_child_properties[0]));
        }
        
                mig_deallocate((vm_address_t)_child_properties, cnt * sizeof(_child_properties[0]));
        }
        
@@ -7969,14 +8924,14 @@ job_mig_transaction_count_for_pid(job_t j, pid_t p, int32_t *cnt, boolean_t *con
 {
        kern_return_t kr = KERN_FAILURE;
        struct ldcred *ldc = runtime_get_caller_creds();
 {
        kern_return_t kr = KERN_FAILURE;
        struct ldcred *ldc = runtime_get_caller_creds();
-       if( (ldc->euid != geteuid()) && (ldc->euid != 0) ) {
+       if ((ldc->euid != geteuid()) && (ldc->euid != 0)) {
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
        
        job_t j_for_pid = jobmgr_find_by_pid_deep(j->mgr, p, false);
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
        
        job_t j_for_pid = jobmgr_find_by_pid_deep(j->mgr, p, false);
-       if( j_for_pid ) {
-               if( j_for_pid->kill_via_shmem ) {
-                       if( j_for_pid->shmem ) {
+       if (j_for_pid) {
+               if (j_for_pid->kill_via_shmem) {
+                       if (j_for_pid->shmem) {
                                *cnt = j_for_pid->shmem->vp_shmem_transaction_cnt;
                                *condemned = j_for_pid->shmem->vp_shmem_flags & VPROC_SHMEM_EXITING;
                                *cnt += *condemned ? 1 : 0;
                                *cnt = j_for_pid->shmem->vp_shmem_transaction_cnt;
                                *condemned = j_for_pid->shmem->vp_shmem_flags & VPROC_SHMEM_EXITING;
                                *cnt += *condemned ? 1 : 0;
@@ -8000,7 +8955,7 @@ kern_return_t
 job_mig_pid_is_managed(job_t j __attribute__((unused)), pid_t p, boolean_t *managed)
 {
        struct ldcred *ldc = runtime_get_caller_creds();
 job_mig_pid_is_managed(job_t j __attribute__((unused)), pid_t p, boolean_t *managed)
 {
        struct ldcred *ldc = runtime_get_caller_creds();
-       if( (ldc->euid != geteuid()) && (ldc->euid != 0) ) {
+       if ((ldc->euid != geteuid()) && (ldc->euid != 0)) {
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
        
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
        
@@ -8008,7 +8963,7 @@ job_mig_pid_is_managed(job_t j __attribute__((unused)), pid_t p, boolean_t *mana
         * directly by launchd as agents.
         */
        job_t j_for_pid = jobmgr_find_by_pid_deep(root_jobmgr, p, false);
         * directly by launchd as agents.
         */
        job_t j_for_pid = jobmgr_find_by_pid_deep(root_jobmgr, p, false);
-       if( j_for_pid && !j_for_pid->anonymous && !j_for_pid->legacy_LS_job ) {
+       if (j_for_pid && !j_for_pid->anonymous && !j_for_pid->legacy_LS_job) {
                *managed = true;
        }
        
                *managed = true;
        }
        
@@ -8020,13 +8975,19 @@ job_mig_port_for_label(job_t j __attribute__((unused)), name_t label, mach_port_
 {
        struct ldcred *ldc = runtime_get_caller_creds();
        kern_return_t kr = BOOTSTRAP_NOT_PRIVILEGED;
 {
        struct ldcred *ldc = runtime_get_caller_creds();
        kern_return_t kr = BOOTSTRAP_NOT_PRIVILEGED;
-       
+
+#if HAVE_SANDBOX
+       if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+#endif
+
        mach_port_t _mp = MACH_PORT_NULL;
        mach_port_t _mp = MACH_PORT_NULL;
-       if( !j->deny_job_creation && (ldc->euid == 0 || ldc->euid == geteuid()) ) {
-               job_t target_j = job_find(label);
-               if( jobmgr_assumes(root_jobmgr, target_j != NULL) ) {
-                       if( target_j->j_port == MACH_PORT_NULL ) {
-                               job_assumes(target_j, job_setup_machport(target_j) == true);
+       if (!j->deny_job_creation && (ldc->euid == 0 || ldc->euid == geteuid())) {
+               job_t target_j = job_find(NULL, label);
+               if (jobmgr_assumes(root_jobmgr, target_j != NULL)) {
+                       if (target_j->j_port == MACH_PORT_NULL) {
+                               (void)job_assumes(target_j, job_setup_machport(target_j) == true);
                        }
                        
                        _mp = target_j->j_port;
                        }
                        
                        _mp = target_j->j_port;
@@ -8042,27 +9003,27 @@ job_mig_port_for_label(job_t j __attribute__((unused)), name_t label, mach_port_
 
 #if !TARGET_OS_EMBEDDED
 kern_return_t
 
 #if !TARGET_OS_EMBEDDED
 kern_return_t
-job_mig_set_security_session(job_t j, uuid_t uuid, mach_port_t session)
+job_mig_set_security_session(job_t j, uuid_t uuid, mach_port_t asport)
 {
        uuid_string_t uuid_str;
        uuid_unparse(uuid, uuid_str);
 {
        uuid_string_t uuid_str;
        uuid_unparse(uuid, uuid_str);
-       job_log(j, LOG_DEBUG, "Setting session %u for UUID %s...", session, uuid_str);
+       job_log(j, LOG_DEBUG, "Setting session %u for UUID %s...", asport, uuid_str);
        
        job_t ji = NULL, jt = NULL;
        
        job_t ji = NULL, jt = NULL;
-       LIST_FOREACH_SAFE( ji, &s_needing_sessions, sle, jt ) {
+       LIST_FOREACH_SAFE(ji, &s_needing_sessions, sle, jt) {
                uuid_string_t uuid_str2;
                uuid_unparse(ji->expected_audit_uuid, uuid_str2);
 
                uuid_string_t uuid_str2;
                uuid_unparse(ji->expected_audit_uuid, uuid_str2);
 
-               if( uuid_compare(uuid, ji->expected_audit_uuid) == 0 ) {
+               if (uuid_compare(uuid, ji->expected_audit_uuid) == 0) {
                        uuid_clear(ji->expected_audit_uuid);
                        uuid_clear(ji->expected_audit_uuid);
-                       if( session != MACH_PORT_NULL  ) {
-                               job_log(ji, LOG_DEBUG, "Job should join session with port %u", session);
-                               mach_port_mod_refs(mach_task_self(), session, MACH_PORT_RIGHT_SEND, 1);
+                       if (asport != MACH_PORT_NULL ) {
+                               job_log(ji, LOG_DEBUG, "Job should join session with port %u", asport);
+                               (void)job_assumes(j, launchd_mport_copy_send(asport) == KERN_SUCCESS);
                        } else {
                                job_log(ji, LOG_DEBUG, "No session to set for job. Using our session.");
                        }
                        
                        } else {
                                job_log(ji, LOG_DEBUG, "No session to set for job. Using our session.");
                        }
                        
-                       ji->audit_session = session;
+                       ji->asport = asport;
                        LIST_REMOVE(ji, needing_session_sle);
                        job_dispatch(ji, false);
                }
                        LIST_REMOVE(ji, needing_session_sle);
                        job_dispatch(ji, false);
                }
@@ -8073,7 +9034,7 @@ job_mig_set_security_session(job_t j, uuid_t uuid, mach_port_t session)
         * We need to release it so that the session goes away when all the jobs
         * referencing it are unloaded.
         */
         * We need to release it so that the session goes away when all the jobs
         * referencing it are unloaded.
         */
-       mach_port_deallocate(mach_task_self(), session);
+       (void)job_assumes(j, launchd_mport_deallocate(asport) == KERN_SUCCESS);
 
        return KERN_SUCCESS;
 }
 
        return KERN_SUCCESS;
 }
@@ -8103,7 +9064,7 @@ jobmgr_find_by_name(jobmgr_t jm, const char *where)
                return jm;
        }
        
                return jm;
        }
        
-       if( strcasecmp(where, VPROCMGR_SESSION_BACKGROUND) == 0 && !pid1_magic ) {
+       if (strcasecmp(where, VPROCMGR_SESSION_BACKGROUND) == 0 && !pid1_magic) {
                jmi = root_jobmgr;
                goto jm_found;
        }
                jmi = root_jobmgr;
                goto jm_found;
        }
@@ -8111,6 +9072,8 @@ jobmgr_find_by_name(jobmgr_t jm, const char *where)
        SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {        
                if (unlikely(jmi->shutting_down)) {
                        continue;
        SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {        
                if (unlikely(jmi->shutting_down)) {
                        continue;
+               } else if (jmi->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN) {
+                       continue;
                } else if (strcasecmp(jmi->name, where) == 0) {
                        goto jm_found;
                } else if (strcasecmp(jmi->name, VPROCMGR_SESSION_BACKGROUND) == 0 && pid1_magic) {
                } else if (strcasecmp(jmi->name, where) == 0) {
                        goto jm_found;
                } else if (strcasecmp(jmi->name, VPROCMGR_SESSION_BACKGROUND) == 0 && pid1_magic) {
@@ -8128,7 +9091,7 @@ jm_found:
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_move_subset(job_t j, mach_port_t target_subset, name_t session_type, mach_port_t audit_session, uint64_t flags)
+job_mig_move_subset(job_t j, mach_port_t target_subset, name_t session_type, mach_port_t asport, uint64_t flags)
 {
        mach_msg_type_number_t l2l_i, l2l_port_cnt = 0;
        mach_port_array_t l2l_ports = NULL;
 {
        mach_msg_type_number_t l2l_i, l2l_port_cnt = 0;
        mach_port_array_t l2l_ports = NULL;
@@ -8159,7 +9122,7 @@ job_mig_move_subset(job_t j, mach_port_t target_subset, name_t session_type, mac
 
        launchd_assert(launch_data_array_get_count(out_obj_array) == l2l_port_cnt);
 
 
        launchd_assert(launch_data_array_get_count(out_obj_array) == l2l_port_cnt);
 
-       if (!job_assumes(j, (jmr = jobmgr_new(j->mgr, reqport, rcvright, false, session_type, false, audit_session)) != NULL)) {
+       if (!job_assumes(j, (jmr = jobmgr_new(j->mgr, reqport, rcvright, false, session_type, false, asport)) != NULL)) {
                kr = BOOTSTRAP_NO_MEMORY;
                goto out;
        }
                kr = BOOTSTRAP_NO_MEMORY;
                goto out;
        }
@@ -8170,7 +9133,7 @@ job_mig_move_subset(job_t j, mach_port_t target_subset, name_t session_type, mac
         * processing an IPC request, we'll do this action before the new job manager can get any IPC
         * requests. This serialization is guaranteed since we are single-threaded in that respect.
         */
         * processing an IPC request, we'll do this action before the new job manager can get any IPC
         * requests. This serialization is guaranteed since we are single-threaded in that respect.
         */
-       if( flags & LAUNCH_GLOBAL_ON_DEMAND ) {
+       if (flags & LAUNCH_GLOBAL_ON_DEMAND) {
                /* This is so awful. */
                /* Remove the job from its current job manager. */
                LIST_REMOVE(j, sle);
                /* This is so awful. */
                /* Remove the job from its current job manager. */
                LIST_REMOVE(j, sle);
@@ -8183,7 +9146,7 @@ job_mig_move_subset(job_t j, mach_port_t target_subset, name_t session_type, mac
                j->mgr = jmr;
                job_set_global_on_demand(j, true);
                
                j->mgr = jmr;
                job_set_global_on_demand(j, true);
                
-               if( !j->holds_ref ) {
+               if (!j->holds_ref) {
                        j->holds_ref = true;
                        runtime_add_ref();
                }
                        j->holds_ref = true;
                        runtime_add_ref();
                }
@@ -8197,19 +9160,19 @@ job_mig_move_subset(job_t j, mach_port_t target_subset, name_t session_type, mac
                pid_t target_pid;
                bool serv_perpid;
 
                pid_t target_pid;
                bool serv_perpid;
 
-               job_assumes(j, obj_at_idx = launch_data_array_get_index(out_obj_array, l2l_i));
-               job_assumes(j, tmp = launch_data_dict_lookup(obj_at_idx, TAKE_SUBSET_PID));
+               (void)job_assumes(j, obj_at_idx = launch_data_array_get_index(out_obj_array, l2l_i));
+               (void)job_assumes(j, tmp = launch_data_dict_lookup(obj_at_idx, TAKE_SUBSET_PID));
                target_pid = (pid_t)launch_data_get_integer(tmp);
                target_pid = (pid_t)launch_data_get_integer(tmp);
-               job_assumes(j, tmp = launch_data_dict_lookup(obj_at_idx, TAKE_SUBSET_PERPID));
+               (void)job_assumes(j, tmp = launch_data_dict_lookup(obj_at_idx, TAKE_SUBSET_PERPID));
                serv_perpid = launch_data_get_bool(tmp);
                serv_perpid = launch_data_get_bool(tmp);
-               job_assumes(j, tmp = launch_data_dict_lookup(obj_at_idx, TAKE_SUBSET_NAME));
+               (void)job_assumes(j, tmp = launch_data_dict_lookup(obj_at_idx, TAKE_SUBSET_NAME));
                serv_name = launch_data_get_string(tmp);
 
                j_for_service = jobmgr_find_by_pid(jmr, target_pid, true);
 
                if (unlikely(!j_for_service)) {
                        /* The PID probably exited */
                serv_name = launch_data_get_string(tmp);
 
                j_for_service = jobmgr_find_by_pid(jmr, target_pid, true);
 
                if (unlikely(!j_for_service)) {
                        /* The PID probably exited */
-                       job_assumes(j, launchd_mport_deallocate(l2l_ports[l2l_i]) == KERN_SUCCESS);
+                       (void)job_assumes(j, launchd_mport_deallocate(l2l_ports[l2l_i]) == KERN_SUCCESS);
                        continue;
                }
 
                        continue;
                }
 
@@ -8232,7 +9195,10 @@ out:
 
        if (kr == 0) {
                if (target_subset) {
 
        if (kr == 0) {
                if (target_subset) {
-                       job_assumes(j, launchd_mport_deallocate(target_subset) == KERN_SUCCESS);
+                       (void)job_assumes(j, launchd_mport_deallocate(target_subset) == KERN_SUCCESS);
+               }
+               if (asport) {
+                       (void)job_assumes(j, launchd_mport_deallocate(asport) == KERN_SUCCESS);
                }
        } else if (jmr) {
                jobmgr_shutdown(jmr);
                }
        } else if (jmr) {
                jobmgr_shutdown(jmr);
@@ -8242,7 +9208,7 @@ out:
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_init_session(job_t j, name_t session_type, mach_port_t audit_session)
+job_mig_init_session(job_t j, name_t session_type, mach_port_t asport)
 {
        job_t j2;
        
 {
        job_t j2;
        
@@ -8281,8 +9247,8 @@ job_mig_init_session(job_t j, name_t session_type, mach_port_t audit_session)
        strcpy(j->mgr->name_init, session_type);
        
        if (job_assumes(j, (j2 = jobmgr_init_session(j->mgr, session_type, false)))) {
        strcpy(j->mgr->name_init, session_type);
        
        if (job_assumes(j, (j2 = jobmgr_init_session(j->mgr, session_type, false)))) {
-               j2->audit_session = audit_session;
-               job_assumes(j, job_dispatch(j2, true));
+               j2->asport = asport;
+               (void)job_assumes(j, job_dispatch(j2, true));
                kr = BOOTSTRAP_SUCCESS;
        }
        
                kr = BOOTSTRAP_SUCCESS;
        }
        
@@ -8290,7 +9256,7 @@ job_mig_init_session(job_t j, name_t session_type, mach_port_t audit_session)
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_switch_to_session(job_t j, mach_port_t requestor_port, name_t session_name, mach_port_t audit_session, mach_port_t *new_bsport)
+job_mig_switch_to_session(job_t j, mach_port_t requestor_port, name_t session_name, mach_port_t asport, mach_port_t *new_bsport)
 {
        struct ldcred *ldc = runtime_get_caller_creds();
        if (!jobmgr_assumes(root_jobmgr, j != NULL)) {
 {
        struct ldcred *ldc = runtime_get_caller_creds();
        if (!jobmgr_assumes(root_jobmgr, j != NULL)) {
@@ -8300,33 +9266,32 @@ job_mig_switch_to_session(job_t j, mach_port_t requestor_port, name_t session_na
 
        job_log(j, LOG_DEBUG, "Job wants to move to %s session.", session_name);
        
 
        job_log(j, LOG_DEBUG, "Job wants to move to %s session.", session_name);
        
-       if( !job_assumes(j, pid1_magic == false) ) {
+       if (!job_assumes(j, pid1_magic == false)) {
                job_log(j, LOG_WARNING, "Switching sessions is not allowed in the system Mach bootstrap.");
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
        
                job_log(j, LOG_WARNING, "Switching sessions is not allowed in the system Mach bootstrap.");
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
        
-       if( !j->anonymous ) {
+       if (!j->anonymous) {
                job_log(j, LOG_NOTICE, "Non-anonymous job tried to switch sessions. Please use LimitLoadToSessionType instead.");
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
        
        jobmgr_t target_jm = jobmgr_find_by_name(root_jobmgr, session_name);
                job_log(j, LOG_NOTICE, "Non-anonymous job tried to switch sessions. Please use LimitLoadToSessionType instead.");
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
        
        jobmgr_t target_jm = jobmgr_find_by_name(root_jobmgr, session_name);
-       if( target_jm == j->mgr ) {
+       if (target_jm == j->mgr) {
                job_log(j, LOG_DEBUG, "Job is already in its desired session (%s).", session_name);
                *new_bsport = target_jm->jm_port;
                return BOOTSTRAP_SUCCESS;
        }
        
                job_log(j, LOG_DEBUG, "Job is already in its desired session (%s).", session_name);
                *new_bsport = target_jm->jm_port;
                return BOOTSTRAP_SUCCESS;
        }
        
-       if( !target_jm ) {
-               target_jm = jobmgr_new(j->mgr, requestor_port, MACH_PORT_NULL, false, session_name, false, audit_session);
-               if( !target_jm ) {
-                       mach_port_deallocate(mach_task_self(), audit_session);
-               } else {
+       if (!target_jm) {
+               target_jm = jobmgr_new(j->mgr, requestor_port, MACH_PORT_NULL, false, session_name, false, asport);
+               if (target_jm) {
                        target_jm->properties |= BOOTSTRAP_PROPERTY_IMPLICITSUBSET;
                        target_jm->properties |= BOOTSTRAP_PROPERTY_IMPLICITSUBSET;
+                       (void)job_assumes(j, launchd_mport_deallocate(asport) == KERN_SUCCESS);
                }
        }
        
                }
        }
        
-       if( !job_assumes(j, target_jm != NULL) ) {
+       if (!job_assumes(j, target_jm != NULL)) {
                job_log(j, LOG_WARNING, "Could not find %s session!", session_name);
                return BOOTSTRAP_NO_MEMORY;
        }
                job_log(j, LOG_WARNING, "Could not find %s session!", session_name);
                return BOOTSTRAP_NO_MEMORY;
        }
@@ -8336,8 +9301,8 @@ job_mig_switch_to_session(job_t j, mach_port_t requestor_port, name_t session_na
        LIST_REMOVE(j, pid_hash_sle);
 
        job_t ji = NULL, jit = NULL;
        LIST_REMOVE(j, pid_hash_sle);
 
        job_t ji = NULL, jit = NULL;
-       LIST_FOREACH_SAFE( ji, &j->mgr->global_env_jobs, global_env_sle, jit ) {
-               if( ji == j ) {
+       LIST_FOREACH_SAFE(ji, &j->mgr->global_env_jobs, global_env_sle, jit) {
+               if (ji == j) {
                        LIST_REMOVE(ji, global_env_sle);
                        break;
                }
                        LIST_REMOVE(ji, global_env_sle);
                        break;
                }
@@ -8347,14 +9312,14 @@ job_mig_switch_to_session(job_t j, mach_port_t requestor_port, name_t session_na
        LIST_INSERT_HEAD(&target_jm->jobs, j, sle);
        LIST_INSERT_HEAD(&target_jm->active_jobs[ACTIVE_JOB_HASH(j->p)], j, pid_hash_sle);
        
        LIST_INSERT_HEAD(&target_jm->jobs, j, sle);
        LIST_INSERT_HEAD(&target_jm->active_jobs[ACTIVE_JOB_HASH(j->p)], j, pid_hash_sle);
        
-       if( ji ) {
+       if (ji) {
                LIST_INSERT_HEAD(&target_jm->global_env_jobs, j, global_env_sle);
        }
        
        /* Move our Mach services over if we're not in a flat namespace. */
                LIST_INSERT_HEAD(&target_jm->global_env_jobs, j, global_env_sle);
        }
        
        /* Move our Mach services over if we're not in a flat namespace. */
-       if( !g_flat_mach_namespace && !SLIST_EMPTY(&j->machservices) ) {
+       if (!g_flat_mach_namespace && !SLIST_EMPTY(&j->machservices)) {
                struct machservice *msi = NULL, *msit = NULL;
                struct machservice *msi = NULL, *msit = NULL;
-               SLIST_FOREACH_SAFE( msi, &j->machservices, sle, msit ) {
+               SLIST_FOREACH_SAFE(msi, &j->machservices, sle, msit) {
                        LIST_REMOVE(msi, name_hash_sle);
                        LIST_INSERT_HEAD(&target_jm->ms_hash[hash_ms(msi->name)], msi, name_hash_sle);
                }
                        LIST_REMOVE(msi, name_hash_sle);
                        LIST_INSERT_HEAD(&target_jm->ms_hash[hash_ms(msi->name)], msi, name_hash_sle);
                }
@@ -8362,7 +9327,7 @@ job_mig_switch_to_session(job_t j, mach_port_t requestor_port, name_t session_na
        
        j->mgr = target_jm;
        
        
        j->mgr = target_jm;
        
-       if( !j->holds_ref ) {
+       if (!j->holds_ref) {
                /* Anonymous jobs which move around are particularly interesting to us, so we want to
                 * stick around while they're still around.
                 * For example, login calls into the PAM launchd module, which moves the process into
                /* Anonymous jobs which move around are particularly interesting to us, so we want to
                 * stick around while they're still around.
                 * For example, login calls into the PAM launchd module, which moves the process into
@@ -8448,25 +9413,25 @@ job_mig_take_subset(job_t j, mach_port_t *reqport, mach_port_t *rcvright,
 
                SLIST_FOREACH(ms, &ji->machservices, sle) {
                        if (job_assumes(j, (tmp_dict = launch_data_alloc(LAUNCH_DATA_DICTIONARY)))) {
 
                SLIST_FOREACH(ms, &ji->machservices, sle) {
                        if (job_assumes(j, (tmp_dict = launch_data_alloc(LAUNCH_DATA_DICTIONARY)))) {
-                               job_assumes(j, launch_data_array_set_index(outdata_obj_array, tmp_dict, cnt2));
+                               (void)job_assumes(j, launch_data_array_set_index(outdata_obj_array, tmp_dict, cnt2));
                        } else {
                                goto out_bad;
                        }
 
                        if (job_assumes(j, (tmp_obj = launch_data_new_string(machservice_name(ms))))) {
                        } else {
                                goto out_bad;
                        }
 
                        if (job_assumes(j, (tmp_obj = launch_data_new_string(machservice_name(ms))))) {
-                               job_assumes(j, launch_data_dict_insert(tmp_dict, tmp_obj, TAKE_SUBSET_NAME));
+                               (void)job_assumes(j, launch_data_dict_insert(tmp_dict, tmp_obj, TAKE_SUBSET_NAME));
                        } else {
                                goto out_bad;
                        }
 
                        if (job_assumes(j, (tmp_obj = launch_data_new_integer((ms->job->p))))) {
                        } else {
                                goto out_bad;
                        }
 
                        if (job_assumes(j, (tmp_obj = launch_data_new_integer((ms->job->p))))) {
-                               job_assumes(j, launch_data_dict_insert(tmp_dict, tmp_obj, TAKE_SUBSET_PID));
+                               (void)job_assumes(j, launch_data_dict_insert(tmp_dict, tmp_obj, TAKE_SUBSET_PID));
                        } else {
                                goto out_bad;
                        }
 
                        if (job_assumes(j, (tmp_obj = launch_data_new_bool((ms->per_pid))))) {
                        } else {
                                goto out_bad;
                        }
 
                        if (job_assumes(j, (tmp_obj = launch_data_new_bool((ms->per_pid))))) {
-                               job_assumes(j, launch_data_dict_insert(tmp_dict, tmp_obj, TAKE_SUBSET_PERPID));
+                               (void)job_assumes(j, launch_data_dict_insert(tmp_dict, tmp_obj, TAKE_SUBSET_PERPID));
                        } else {
                                goto out_bad;
                        }
                        } else {
                                goto out_bad;
                        }
@@ -8474,12 +9439,12 @@ job_mig_take_subset(job_t j, mach_port_t *reqport, mach_port_t *rcvright,
                        ports[cnt2] = machservice_port(ms);
 
                        /* Increment the send right by one so we can shutdown the jobmgr cleanly */
                        ports[cnt2] = machservice_port(ms);
 
                        /* Increment the send right by one so we can shutdown the jobmgr cleanly */
-                       jobmgr_assumes(jm, (errno = mach_port_mod_refs(mach_task_self(), ports[cnt2], MACH_PORT_RIGHT_SEND, 1)) == 0);
+                       (void)jobmgr_assumes(jm, (errno = launchd_mport_copy_send(ports[cnt2])) == KERN_SUCCESS);
                        cnt2++;
                }
        }
 
                        cnt2++;
                }
        }
 
-       job_assumes(j, cnt == cnt2);
+       (void)job_assumes(j, cnt == cnt2);
 
        runtime_ktrace0(RTKT_LAUNCHD_DATA_PACK);
        packed_size = launch_data_pack(outdata_obj_array, (void *)*outdata, *outdataCnt, NULL, NULL);
 
        runtime_ktrace0(RTKT_LAUNCHD_DATA_PACK);
        packed_size = launch_data_pack(outdata_obj_array, (void *)*outdata, *outdataCnt, NULL, NULL);
@@ -8543,7 +9508,7 @@ job_mig_subset(job_t j, mach_port_t requestorport, mach_port_t *subsetportp)
        char name[NAME_MAX];
        snprintf(name, sizeof(name), "%s[%i].subset.%i", j->anonymous ? j->prog : j->label, j->p, MACH_PORT_INDEX(requestorport));
 
        char name[NAME_MAX];
        snprintf(name, sizeof(name), "%s[%i].subset.%i", j->anonymous ? j->prog : j->label, j->p, MACH_PORT_INDEX(requestorport));
 
-       if (!job_assumes(j, (jmr = jobmgr_new(j->mgr, requestorport, MACH_PORT_NULL, false, name, true, j->audit_session)) != NULL)) {
+       if (!job_assumes(j, (jmr = jobmgr_new(j->mgr, requestorport, MACH_PORT_NULL, false, name, true, j->asport)) != NULL)) {
                if (unlikely(requestorport == MACH_PORT_NULL)) {
                        return BOOTSTRAP_NOT_PRIVILEGED;
                }
                if (unlikely(requestorport == MACH_PORT_NULL)) {
                        return BOOTSTRAP_NOT_PRIVILEGED;
                }
@@ -8556,7 +9521,7 @@ job_mig_subset(job_t j, mach_port_t requestorport, mach_port_t *subsetportp)
        /* A job could create multiple subsets, so only add a reference the first time
         * it does so we don't have to keep a count.
         */
        /* A job could create multiple subsets, so only add a reference the first time
         * it does so we don't have to keep a count.
         */
-       if( j->anonymous && !j->holds_ref ) {
+       if (j->anonymous && !j->holds_ref) {
                j->holds_ref = true;
                runtime_add_ref();
        }
                j->holds_ref = true;
                runtime_add_ref();
        }
@@ -8565,169 +9530,507 @@ job_mig_subset(job_t j, mach_port_t requestorport, mach_port_t *subsetportp)
        return BOOTSTRAP_SUCCESS;
 }
 
        return BOOTSTRAP_SUCCESS;
 }
 
-kern_return_t
-job_mig_embedded_wait(job_t j, name_t targetlabel, integer_t *waitstatus)
-{
-       job_t otherj;
-
-       if (!launchd_assumes(j != NULL)) {
-               return BOOTSTRAP_NO_MEMORY;
-       }
-
-       if (unlikely(!(otherj = job_find(targetlabel)))) {
-               return BOOTSTRAP_UNKNOWN_SERVICE;
-       }
-
-       *waitstatus = j->last_exit_status;
+#ifndef __LAUNCH_DISABLE_XPC_SUPPORT__
+job_t
+xpc_domain_import_service(jobmgr_t jm, launch_data_t pload)
+{
+       jobmgr_t where2put = NULL;
+
+       launch_data_t destname = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_XPCDOMAIN);
+       if (destname) {
+               if (launch_data_get_type(destname) == LAUNCH_DATA_STRING) {
+                       const char *str = launch_data_get_string(destname);
+                       if (strcmp(str, XPC_DOMAIN_TYPE_SYSTEM) == 0) {
+                               where2put = _s_xpc_system_domain;
+                       } else if (strcmp(str, XPC_DOMAIN_TYPE_PERUSER) == 0) {
+                               where2put = jobmgr_find_xpc_per_user_domain(jm, jm->req_euid);
+                       } else if (strcmp(str, XPC_DOMAIN_TYPE_PERSESSION) == 0) {
+                               where2put = jobmgr_find_xpc_per_session_domain(jm, jm->req_asid);
+                       } else {
+                               jobmgr_log(jm, LOG_ERR, "Invalid XPC domain type: %s", str);
+                               errno = EINVAL;
+                       }
+               } else {
+                       jobmgr_log(jm, LOG_ERR, "XPC domain type is not a string.");
+                       errno = EINVAL;
+               }
 
 
-       return 0;
+               if (where2put) {
+                       launch_data_t mi = NULL;
+                       if ((mi = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_MULTIPLEINSTANCES))) {
+                               if (launch_data_get_type(mi) == LAUNCH_DATA_BOOL && launch_data_get_bool(mi)) {
+                                       jobmgr_log(where2put, LOG_ERR, "Multiple-instance services are not supported in this domain.");
+                                       where2put = NULL;
+                                       errno = EINVAL;
+                               }
+                       }
+               }
+       } else {
+               where2put = jm;
+       }
+
+       job_t j = NULL;
+       if (where2put) {
+               jobmgr_log(where2put, LOG_DEBUG, "Importing service...");
+               j = jobmgr_import2(where2put, pload);
+               if (j) {
+                       j->xpc_service = true;
+                       if (where2put->xpc_singleton) {
+                               /* If the service was destined for one of the global domains,
+                                * then we have to alias it into our local domain to reserve the
+                                * name.
+                                */
+                               job_t ja = job_new_alias(jm, j);
+                               if (!ja) {
+                                       /* If we failed to alias the job because of a conflict over
+                                        * the label, then we remove it from the global domain. We
+                                        * don't want to risk having imported a malicious job into
+                                        * one of the global domains.
+                                        */
+                                       if (errno != EEXIST) {
+                                               job_assumes(j, errno == 0);
+                                       } else {
+                                               job_log(j, LOG_ERR, "Failed to alias job into: %s", where2put->name);
+                                       }
+
+                                       job_remove(j);
+                               } else {
+                                       ja->xpc_service = true;
+                                       j = ja;
+                               }
+                       }
+               }
+       }
+
+       return j;
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_kickstart(job_t j, name_t targetlabel, pid_t *out_pid, mach_port_t *out_name_port, mach_port_t *obsrvr_port, unsigned int flags)
+xpc_domain_import2(job_t j, mach_port_t reqport, mach_port_t dport)
 {
 {
-       struct ldcred *ldc = runtime_get_caller_creds();
-       job_t otherj;
+       if (unlikely(!pid1_magic)) {
+               job_log(j, LOG_ERR, "XPC domains may only reside in PID 1.");
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+       if (!MACH_PORT_VALID(reqport)) {
+               return BOOTSTRAP_UNKNOWN_SERVICE;
+       }
 
 
-       if (!launchd_assumes(j != NULL)) {
-               return BOOTSTRAP_NO_MEMORY;
+       kern_return_t kr = BOOTSTRAP_NO_MEMORY;
+       /* All XPC domains are children of the root job manager. What we're creating
+        * here is really just a skeleton. By creating it, we're adding reqp to our
+        * port set. It will have two messages on it. The first specifies the
+        * environment of the originator. This is so we can cache it and hand it to
+        * xpcproxy to bootstrap our services. The second is the set of jobs that is
+        * to be bootstrapped in.
+        */
+       jobmgr_t jm = jobmgr_new(root_jobmgr, reqport, dport, false, NULL, true, MACH_PORT_NULL);
+       if (job_assumes(j, jm != NULL)) {
+               jm->properties |= BOOTSTRAP_PROPERTY_XPC_DOMAIN;
+               jm->shortdesc = "private";
+               kr = BOOTSTRAP_SUCCESS;
        }
 
        }
 
-       if (unlikely(!(otherj = job_find(targetlabel)))) {
+       return kr;
+}
+
+kern_return_t
+xpc_domain_set_environment(job_t j, mach_port_t rp, mach_port_t bsport, mach_port_t excport, vm_offset_t ctx, mach_msg_type_number_t ctx_sz)
+{
+       if (!j) {
+               /* Due to the whacky nature of XPC service bootstrapping, we can end up
+                * getting this message long after the requesting process has gone away.
+                * See <rdar://problem/8593143>.
+                */
                return BOOTSTRAP_UNKNOWN_SERVICE;
        }
 
                return BOOTSTRAP_UNKNOWN_SERVICE;
        }
 
-#if TARGET_OS_EMBEDDED
-       bool allow_non_root_kickstart = j->username && otherj->username && ( strcmp(j->username, otherj->username) == 0 );
-#else
-       bool allow_non_root_kickstart = false;
-#endif
+       jobmgr_t jm = j->mgr;
+       if (!(jm->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+       
+       if (jm->req_asport != MACH_PORT_NULL) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+       
+       struct ldcred *ldc = runtime_get_caller_creds();
+       struct proc_bsdshortinfo proc;
+       if (proc_pidinfo(ldc->pid, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
+               if (errno != ESRCH) {
+                       jobmgr_assumes(jm, errno == 0);
+               }
 
 
-       if( ldc->euid != 0 && ldc->euid != geteuid() && !allow_non_root_kickstart ) {
+               jm->error = errno;
+               jobmgr_remove(jm);
+               return BOOTSTRAP_NO_MEMORY;
+       }
+
+       if (!jobmgr_assumes(jm, audit_session_port(ldc->asid, &jm->req_asport) == 0)) {
+               jm->error = EPERM;
+               jobmgr_remove(jm);
+               job_log(j, LOG_ERR, "Failed to get port for ASID: %u", ldc->asid);
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
 
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
 
-       if( otherj->p && (flags & VPROCFLAG_STALL_JOB_EXEC) ) {
-               return BOOTSTRAP_SERVICE_ACTIVE;
+       (void)snprintf(jm->name_init, NAME_MAX, "com.apple.xpc.domain.%s[%i]", proc.pbsi_comm, ldc->pid);
+       strlcpy(jm->owner, proc.pbsi_comm, sizeof(jm->owner));
+       jm->req_bsport = bsport;
+       jm->req_excport = excport;
+       jm->req_rport = rp;
+       jm->req_ctx = ctx;
+       jm->req_ctx_sz = ctx_sz;
+       jm->req_pid = ldc->pid;
+       jm->req_euid = ldc->euid;
+       jm->req_egid = ldc->egid;
+       jm->req_asid = ldc->asid;
+       
+       return KERN_SUCCESS;
+}
+
+kern_return_t
+xpc_domain_load_services(job_t j, vm_offset_t services_buff, mach_msg_type_number_t services_sz)
+{
+       if (!j) {
+               return BOOTSTRAP_UNKNOWN_SERVICE;
        }
 
        }
 
-       otherj->stall_before_exec = ( flags & VPROCFLAG_STALL_JOB_EXEC );
-       otherj = job_dispatch(otherj, true);
+       /* This is just for XPC domains (for now). */
+       if (!(j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+       if (j->mgr->session_initialized) {
+               jobmgr_log(j->mgr, LOG_ERR, "Attempt to initialize an already-initialized XPC domain.");
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
 
 
-       if (!job_assumes(j, otherj && otherj->p)) {
-               /* <rdar://problem/6787083> Clear this flag if we failed to start the job. */
-               otherj->stall_before_exec = false;
+       size_t offset = 0;
+       launch_data_t services = launch_data_unpack((void *)services_buff, services_sz, NULL, 0, &offset, NULL);
+       if (!jobmgr_assumes(j->mgr, services != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
 
                return BOOTSTRAP_NO_MEMORY;
        }
 
-       /* If any of these proceeding steps fail, we return an error to the client.
-        * the problem is that, if the client has requested the job be stalled before
-        * exec(2), the client won't be able to uncork the fork(2), leaving the job
-        * forever stalled until the client tries again and we successfully start
-        * the job.
-        *
-        * See <rdar://problem/6787083> for more about the implications.
-        *
-        * Fortunately, these next actions should pretty much never fail. In the
-        * future, we should look at cleaning up after these failures if the job
-        * was started in a stalled state.
-        */
+       size_t i = 0;
+       size_t c = launch_data_array_get_count(services);
+       for (i = 0; i < c; i++) {
+               job_t nj = NULL;
+               launch_data_t ploadi = launch_data_array_get_index(services, i);
+               if (!(nj = xpc_domain_import_service(j->mgr, ploadi))) {
+                       /* If loading one job fails, just fail the whole thing. At this
+                        * point, xpchelper should receive the failure and then just refuse
+                        * to launch the application, since its XPC services could not be
+                        * fully bootstrapped.
+                        *
+                        * Take care to not reference the job or its manager after this
+                        * point.
+                        */
+                       if (errno == EINVAL) {
+                               jobmgr_log(j->mgr, LOG_ERR, "Service at index is not valid: %lu", i);
+                       } else if (errno == EEXIST) {
+                               /* If we get back EEXIST, we know that the payload was a
+                                * dictionary with a label. But, well, I guess it never hurts to
+                                * check.
+                                */
+                               char *label = "(bogus)";
+                               if (launch_data_get_type(ploadi) == LAUNCH_DATA_DICTIONARY) {
+                                       launch_data_t llabel = launch_data_dict_lookup(ploadi, LAUNCH_JOBKEY_LABEL);
+                                       if (launch_data_get_type(llabel) == LAUNCH_DATA_STRING) {
+                                               label = (char *)launch_data_get_string(llabel);
+                                       }
+                               }
+                               jobmgr_log(j->mgr, LOG_ERR, "Service name conflict: %s", label);
+                       }
 
 
-       kern_return_t kr = task_name_for_pid(mach_task_self(), otherj->p, out_name_port);
-       if (!job_assumes(j, kr == 0)) {
-               return kr;
+                       j->mgr->error = errno;
+                       jobmgr_log(j->mgr, LOG_ERR, "Obliterating domain.");
+                       jobmgr_remove(j->mgr);
+                       break;
+               } else {
+                       jobmgr_log(j->mgr, LOG_DEBUG, "Imported service %s", nj->label);
+                       job_dispatch(nj, false);
+               }
        }
 
        }
 
-       if (!job_setup_machport(otherj)) {
-               return BOOTSTRAP_NO_MEMORY;
+       kern_return_t result = BOOTSTRAP_NO_MEMORY;
+       if (i == c) {
+               j->mgr->session_initialized = true;
+               (void)jobmgr_assumes(j->mgr, xpc_call_wakeup(j->mgr->req_rport, BOOTSTRAP_SUCCESS) == KERN_SUCCESS);
+               j->mgr->req_rport = MACH_PORT_NULL;
+
+               /* Returning a failure code will destroy the message, whereas returning
+                * success will not, so we need to clean up here.
+                */
+               mig_deallocate(services_buff, services_sz);
+               result = BOOTSTRAP_SUCCESS;
        }
        }
-       
-       *obsrvr_port = otherj->j_port;
-       *out_pid = otherj->p;
 
 
-       return 0;
+       return result;
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_wait(job_t j, mach_port_t srp, integer_t *waitstatus)
+xpc_domain_check_in(job_t j, mach_port_t *bsport, mach_port_t *sbsport, mach_port_t *excport, mach_port_t *asport, uint32_t *uid, uint32_t *gid, int32_t *asid, vm_offset_t *ctx, mach_msg_type_number_t *ctx_sz)
 {
 {
-#if 0
-       if (!launchd_assumes(j != NULL)) {
-               return BOOTSTRAP_NO_MEMORY;
+       if (!jobmgr_assumes(root_jobmgr, j != NULL)) {
+               return BOOTSTRAP_UNKNOWN_SERVICE;
        }
        }
-       return job_handle_mpm_wait(j, srp, waitstatus);
-#else
-       if( false ) {
-               /* To make the compiler happy. */
-               job_handle_mpm_wait(NULL, MACH_PORT_NULL, NULL);
+       jobmgr_t jm = j->mgr;
+       if (!(jm->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
        }
        }
-       struct ldcred *ldc = runtime_get_caller_creds();
-       job_t calling_j = jobmgr_find_by_pid(j->mgr, ldc->pid, true);
        
        
-       return job_mig_wait2(calling_j, j, srp, waitstatus, true);
-#endif
+       if (jm->req_asport == MACH_PORT_NULL) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+       
+       *bsport = jm->req_bsport;
+       *sbsport = root_jobmgr->jm_port;
+       *excport = jm->req_excport;
+       *asport = jm->req_asport;
+       *uid = jm->req_euid;
+       *gid = jm->req_egid;
+       *asid = jm->req_asid;
+       
+       *ctx = jm->req_ctx;
+       *ctx_sz = jm->req_ctx_sz;
+       
+       return KERN_SUCCESS;
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_wait2(job_t j, job_t target_j, mach_port_t srp, integer_t *status, boolean_t legacy)
+xpc_domain_get_service_name(job_t j, event_name_t name)
 {
 {
-       if( !launchd_assumes(j != NULL) ) {
+       if (!j) {
                return BOOTSTRAP_NO_MEMORY;
        }
                return BOOTSTRAP_NO_MEMORY;
        }
-       if( !launchd_assumes(target_j != NULL) ) {
-               return BOOTSTRAP_NO_MEMORY;
+       if (!j->xpc_service) {
+               jobmgr_log(j->mgr, LOG_ERR, "Attempt to get service name by non-XPC service: %s", j->label);
+               return BOOTSTRAP_NOT_PRIVILEGED;
        }
        }
-       if( !launchd_assumes(status != NULL) ) {
-               return BOOTSTRAP_NO_MEMORY;
+
+       struct machservice * ms = SLIST_FIRST(&j->machservices);
+       if (!ms) {
+               jobmgr_log(j->mgr, LOG_ERR, "Attempt to get service name of job with no machservices: %s", j->label);
+               return BOOTSTRAP_UNKNOWN_SERVICE;
        }
        }
-       
-       /* See rdar://problem/7084138 for why we do the second part of this check.
-        * Basically, since Finder, Dock and SystemUIServer are now real launchd
-        * jobs, they don't get removed after exiting, like legacy LaunchServices
-        * jobs do. So there's a race. coreservicesd came in asking for the exit
-        * status after we'd relaunched Finder, so Finder's PID isn't 0.
-        *
-        * So we check to make sure the target job isn't a LaunchServices job and
-        * that the request is coming through the legacy path (mpm_wait()). If so,
-        * we return the last exit status, regardless of the current PID value.
-        */
-       if( target_j->p == 0 || (!target_j->legacy_LS_job && legacy) ) {
-               *status = target_j->last_exit_status;
-               return BOOTSTRAP_SUCCESS;
+
+       (void)strlcpy(name, ms->name, sizeof(event_name_t));
+       return BOOTSTRAP_SUCCESS;
+}
+#endif
+
+kern_return_t
+xpc_events_get_channel_name(job_t j __attribute__((unused)), event_name_t stream __attribute__((unused)), uint64_t token __attribute__((unused)), event_name_t name __attribute__((unused)))
+{
+       return KERN_FAILURE;
+}
+
+kern_return_t
+xpc_events_get_event_name(job_t j, event_name_t stream, uint64_t token, event_name_t name)
+{
+       struct externalevent *event = externalevent_find(stream, token);
+       if (event && j->event_monitor) {
+               (void)strcpy(name, event->name);
+       } else {
+               event = NULL;
        }
        }
+
+       return event ? BOOTSTRAP_SUCCESS : BOOTSTRAP_UNKNOWN_SERVICE;
+}
        
        
-       if( !job_assumes(j, waiting4exit_new(target_j, srp, legacy) == true) ) {
-               return BOOTSTRAP_NO_MEMORY;
+kern_return_t
+xpc_events_set_event(job_t j, event_name_t stream, event_name_t key, vm_offset_t event, mach_msg_type_number_t eventCnt)
+{
+       if (j->anonymous) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
        }
        }
-       
-       return MIG_NO_REPLY;
+
+       struct externalevent *eei = NULL;
+       LIST_FOREACH(eei, &j->events, job_le) {
+               if (strcmp(eei->name, key) == 0 && strcmp(eei->sys->name, stream) == 0) {
+                       externalevent_delete(eei);
+                       eventsystem_ping();
+                       break;
+               }
+       }
+
+       bool success = false;
+       struct eventsystem *es = eventsystem_find(stream);
+       if (!es) {
+               es = eventsystem_new(stream);
+               (void)job_assumes(j, es != NULL);
+       }
+
+       if (es) {
+               size_t offset = 0;
+               launch_data_t unpacked = launch_data_unpack((void *)event, eventCnt, NULL, 0, &offset, 0);
+               if (unpacked && launch_data_get_type(unpacked) == LAUNCH_DATA_DICTIONARY) {
+                       success = externalevent_new(j, es, key, unpacked);
+               }
+       }
+
+       if (!success) {
+               mig_deallocate(event, eventCnt);
+       }
+
+       return KERN_SUCCESS;
 }
 
 kern_return_t
 }
 
 kern_return_t
-job_mig_uncork_fork(job_t j)
+xpc_events_get_event(job_t j, event_name_t stream, event_name_t key, vm_offset_t *event, mach_msg_type_number_t *eventCnt)
+{
+       struct externalevent *eei = NULL;
+       LIST_FOREACH(eei, &j->events, job_le) {
+               if (strcmp(eei->name, key) == 0 && strcmp(eei->sys->name, stream) == 0) {
+                       /* Big enough. */
+                       *eventCnt = 10 * 1024;
+                       mig_allocate(event, *eventCnt);
+
+                       size_t sz = launch_data_pack(eei->event, (void *)*event, *eventCnt, NULL, NULL);
+                       if (!job_assumes(j, sz != 0)) {
+                               mig_deallocate(*event, *eventCnt);
+                               return BOOTSTRAP_NO_MEMORY;
+                       }
+
+                       return BOOTSTRAP_SUCCESS;
+               }
+       }
+
+       return BOOTSTRAP_UNKNOWN_SERVICE;
+}
+
+struct machservice *
+xpc_events_find_channel(job_t j, event_name_t stream, mach_port_t *p)
 {
 {
+       struct machservice *msi = NULL;
+       SLIST_FOREACH(msi, &j->machservices, sle) {
+               if (strcmp(stream, msi->name) == 0) {
+                       break;
+               }
+       }
+
+       if (!msi) {
+               mach_port_t sp = MACH_PORT_NULL;
+               msi = machservice_new(j, stream, &sp, false);
+               if (job_assumes(j, msi)) {
+                       /* Hack to keep this from being publicly accessible through
+                        * bootstrap_look_up().
+                        */
+                       LIST_REMOVE(msi, name_hash_sle);
+                       msi->event_channel = true;
+                       *p = sp;
+
+                       machservice_watch(j, msi);
+               } else {
+                       errno = BOOTSTRAP_NO_MEMORY;
+               }
+       } else {
+               if (!msi->event_channel) {
+                       job_log(j, LOG_ERR, "This job registered a MachService name identical to the requested event channel name: %s", stream);
+                       msi = NULL;
+                       errno = BOOTSTRAP_NAME_IN_USE;
+               } else {
+                       *p = msi->port;
+               }
+       }
+
+       return msi;
+}
+
+kern_return_t
+xpc_events_channel_check_in(job_t j, event_name_t stream, uint64_t flags __attribute__((unused)), mach_port_t *p)
+{
+       struct machservice *ms = xpc_events_find_channel(j, stream, p);
+       if (ms) {
+               if (ms->isActive) {
+                       job_log(j, LOG_ERR, "Attempt to check in on event channel multiple times: %s", stream);
+                       *p = MACH_PORT_NULL;
+                       errno = BOOTSTRAP_SERVICE_ACTIVE;
+               } else {
+                       job_checkin(j);
+                       machservice_request_notifications(ms);
+                       errno = BOOTSTRAP_SUCCESS;
+               }
+       }
+
+       return errno;
+}
+
+kern_return_t
+xpc_events_channel_look_up(job_t j, event_name_t stream, event_token_t token, uint64_t flags __attribute__((unused)), mach_port_t *p)
+{
+       if (!j->event_monitor) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+
+       struct externalevent *ee = externalevent_find(stream, token);
+       if (!ee) {
+               return BOOTSTRAP_UNKNOWN_SERVICE;
+       }
+
+       struct machservice *ms = xpc_events_find_channel(ee->job, stream, p);
+       if (ms) {
+               errno = BOOTSTRAP_SUCCESS;
+       }
+
+       return errno;
+}
+
+kern_return_t
+job_mig_kickstart(job_t j, name_t targetlabel, pid_t *out_pid, unsigned int flags)
+{
+       struct ldcred *ldc = runtime_get_caller_creds();
+       job_t otherj;
+
        if (!launchd_assumes(j != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
 
        if (!launchd_assumes(j != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
 
-       if (unlikely(!j->stall_before_exec)) {
-               job_log(j, LOG_WARNING, "Attempt to uncork a job that isn't in the middle of a fork().");
-               return 1;
+       if (unlikely(!(otherj = job_find(NULL, targetlabel)))) {
+               return BOOTSTRAP_UNKNOWN_SERVICE;
        }
 
        }
 
-       job_uncork_fork(j);
-       j->stall_before_exec = false;
+#if TARGET_OS_EMBEDDED
+       bool allow_non_root_kickstart = j->username && otherj->username && (strcmp(j->username, otherj->username) == 0);
+#else
+       bool allow_non_root_kickstart = false;
+#endif
+
+       if (ldc->euid != 0 && ldc->euid != geteuid() && !allow_non_root_kickstart) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+
+#if HAVE_SANDBOX
+       if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+#endif
+
+       if (otherj->p && (flags & VPROCFLAG_STALL_JOB_EXEC)) {
+               return BOOTSTRAP_SERVICE_ACTIVE;
+       }
+
+       otherj->stall_before_exec = (flags & VPROCFLAG_STALL_JOB_EXEC);
+       otherj = job_dispatch(otherj, true);
+
+       if (!job_assumes(j, otherj && otherj->p)) {
+               /* <rdar://problem/6787083> Clear this flag if we failed to start the job. */
+               otherj->stall_before_exec = false;
+               return BOOTSTRAP_NO_MEMORY;
+       }
+
+       *out_pid = otherj->p;
+
        return 0;
 }
 
 kern_return_t
        return 0;
 }
 
 kern_return_t
-job_mig_spawn(job_t j, vm_offset_t indata, mach_msg_type_number_t indataCnt, mach_port_t audit_session, pid_t *child_pid, mach_port_t *obsvr_port)
+job_mig_spawn_internal(job_t j, vm_offset_t indata, mach_msg_type_number_t indataCnt, mach_port_t asport, job_t *outj)
 {
 {
-       launch_data_t input_obj = NULL;
+       launch_data_t jobdata = NULL;
        size_t data_offset = 0;
        struct ldcred *ldc = runtime_get_caller_creds();
        job_t jr;
        size_t data_offset = 0;
        struct ldcred *ldc = runtime_get_caller_creds();
        job_t jr;
-
+       
        if (!launchd_assumes(j != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
        if (!launchd_assumes(j != NULL)) {
                return BOOTSTRAP_NO_MEMORY;
        }
@@ -8741,7 +10044,7 @@ job_mig_spawn(job_t j, vm_offset_t indata, mach_msg_type_number_t indataCnt, mac
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
 #endif
                return BOOTSTRAP_NOT_PRIVILEGED;
        }
 #endif
-
+       
        if (unlikely(pid1_magic && ldc->euid && ldc->uid)) {
                job_log(j, LOG_DEBUG, "Punting spawn to per-user-context");
                return VPROC_ERR_TRY_PER_USER;
        if (unlikely(pid1_magic && ldc->euid && ldc->uid)) {
                job_log(j, LOG_DEBUG, "Punting spawn to per-user-context");
                return VPROC_ERR_TRY_PER_USER;
@@ -8752,21 +10055,44 @@ job_mig_spawn(job_t j, vm_offset_t indata, mach_msg_type_number_t indataCnt, mac
        }
 
        runtime_ktrace0(RTKT_LAUNCHD_DATA_UNPACK);
        }
 
        runtime_ktrace0(RTKT_LAUNCHD_DATA_UNPACK);
-       if (!job_assumes(j, (input_obj = launch_data_unpack((void *)indata, indataCnt, NULL, 0, &data_offset, NULL)) != NULL)) {
+       if (!job_assumes(j, (jobdata = launch_data_unpack((void *)indata, indataCnt, NULL, 0, &data_offset, NULL)) != NULL)) {
                return 1;
        }
 
        jobmgr_t target_jm = jobmgr_find_by_name(j->mgr, NULL);
                return 1;
        }
 
        jobmgr_t target_jm = jobmgr_find_by_name(j->mgr, NULL);
-       if( !jobmgr_assumes(j->mgr, target_jm != NULL) ) {
-               jobmgr_log(j->mgr, LOG_NOTICE, "%s() can't find its session!", __func__);
+       if (!jobmgr_assumes(j->mgr, target_jm != NULL)) {
+               jobmgr_log(j->mgr, LOG_ERR, "This API can only be used by a process running within an Aqua session.");
                return 1;
        }
 
                return 1;
        }
 
-       jr = jobmgr_import2(target_jm ?: j->mgr, input_obj);
-       
-       if (!job_assumes(j, jr != NULL)) {
+       jr = jobmgr_import2(target_jm ?: j->mgr, jobdata);
+
+       launch_data_t label = NULL;
+       launch_data_t wait4debugger = NULL;
+       if (!jr) {
                switch (errno) {
                case EEXIST:
                switch (errno) {
                case EEXIST:
+                       /* If EEXIST was returned, we know that there is a label string in
+                        * the dictionary. So we don't need to check the types here; that
+                        * has already been done.
+                        */
+                       label = launch_data_dict_lookup(jobdata, LAUNCH_JOBKEY_LABEL);
+                       jr = job_find(NULL, launch_data_get_string(label));
+                       if (job_assumes(j, jr != NULL) && !jr->p) {
+                               wait4debugger = launch_data_dict_lookup(jobdata, LAUNCH_JOBKEY_WAITFORDEBUGGER);
+                               if (wait4debugger && launch_data_get_type(wait4debugger) == LAUNCH_DATA_BOOL) {
+                                       if (launch_data_get_bool(wait4debugger)) {
+                                               /* If the job exists, we're going to kick-start it, but
+                                                * we need to give the caller the opportunity to start
+                                                * it suspended if it so desires. But this will only
+                                                * take effect if the job isn't running.
+                                                */
+                                               jr->wait4debugger_oneshot = true;
+                                       }
+                               }
+                       }
+
+                       *outj = jr;
                        return BOOTSTRAP_NAME_IN_USE;
                default:
                        return BOOTSTRAP_NO_MEMORY;
                        return BOOTSTRAP_NAME_IN_USE;
                default:
                        return BOOTSTRAP_NO_MEMORY;
@@ -8779,34 +10105,157 @@ job_mig_spawn(job_t j, vm_offset_t indata, mach_msg_type_number_t indataCnt, mac
 
        jr->legacy_LS_job = true;
        jr->abandon_pg = true;
 
        jr->legacy_LS_job = true;
        jr->abandon_pg = true;
-       jr->stall_before_exec = jr->wait4debugger;
-       jr->wait4debugger = false;
-       jr->audit_session = audit_session;
+       jr->asport = asport;
        uuid_clear(jr->expected_audit_uuid);
        uuid_clear(jr->expected_audit_uuid);
-
        jr = job_dispatch(jr, true);
 
        if (!job_assumes(j, jr != NULL)) {
        jr = job_dispatch(jr, true);
 
        if (!job_assumes(j, jr != NULL)) {
-               return BOOTSTRAP_NO_MEMORY;
-       }
-
-       if (!job_assumes(jr, jr->p)) {
                job_remove(jr);
                return BOOTSTRAP_NO_MEMORY;
        }
 
                job_remove(jr);
                return BOOTSTRAP_NO_MEMORY;
        }
 
-       if (!job_setup_machport(jr)) {
+       if (!job_assumes(jr, jr->p)) {
                job_remove(jr);
                return BOOTSTRAP_NO_MEMORY;
        }
 
        job_log(jr, LOG_DEBUG, "Spawned by PID %u: %s", j->p, j->label);
                job_remove(jr);
                return BOOTSTRAP_NO_MEMORY;
        }
 
        job_log(jr, LOG_DEBUG, "Spawned by PID %u: %s", j->p, j->label);
+       *outj = jr;
 
 
-       *child_pid = jr->p;
-       *obsvr_port = jr->j_port;
+       return BOOTSTRAP_SUCCESS;
+}
+
+kern_return_t
+job_mig_spawn2(job_t j, mach_port_t rp, vm_offset_t indata, mach_msg_type_number_t indataCnt, mach_port_t asport, pid_t *child_pid, mach_port_t *obsvr_port)
+{
+       job_t nj = NULL;
+       kern_return_t kr = job_mig_spawn_internal(j, indata, indataCnt, asport, &nj);
+       if (likely(kr == KERN_SUCCESS)) {
+               if (job_setup_exit_port(nj) != KERN_SUCCESS) {
+                       job_remove(nj);
+                       kr = BOOTSTRAP_NO_MEMORY;
+               } else {
+                       /* Do not return until the job has called exec(3), thereby making it
+                        * safe for the caller to send it SIGCONT.
+                        *
+                        * <rdar://problem/9042798>
+                        */
+                       nj->spawn_reply_port = rp;
+                       kr = MIG_NO_REPLY;
+               }
+       } else if (kr == BOOTSTRAP_NAME_IN_USE) {
+               bool was_running = nj->p;
+               if (job_dispatch(nj, true)) {
+                       if (!was_running) {
+                               job_log(nj, LOG_DEBUG, "Job exists but is not running. Kick-starting.");
+                               
+                               if (job_setup_exit_port(nj) == KERN_SUCCESS) {
+                                       nj->spawn_reply_port = rp;
+                                       kr = MIG_NO_REPLY;
+                               } else {
+                                       kr = BOOTSTRAP_NO_MEMORY;
+                               }
+                       } else {
+                               *obsvr_port = MACH_PORT_NULL;
+                               *child_pid = nj->p;
+                               kr = KERN_SUCCESS;
+                       }
+               } else {
+                       job_log(nj, LOG_ERR, "Failed to dispatch job, requestor: %s", j->label);
+                       kr = BOOTSTRAP_UNKNOWN_SERVICE;
+               }
+       }
 
        mig_deallocate(indata, indataCnt);
 
        mig_deallocate(indata, indataCnt);
+       return kr;
+}
+
+kern_return_t
+job_mig_event_source_check_in(job_t j, name_t name, mach_port_t ping_port, vm_offset_t *outval,        mach_msg_type_number_t *outvalCnt, uint64_t *tokens)
+{
+       if (!j || !j->event_monitor) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+
+       /* Update our ping-port. One ping will force all the notification systems
+        * to check in, so they'll all give us send-once rights. It doesn't really
+        * matter which one we keep around. It's not the most efficient thing ever,
+        * but keep in mind that, by doing this over one channel, we can do it over
+        * the job's MachService. This means that we'll get it back when the job dies,
+        * and we can create ourselves a send-once right if we didn't have one already,
+        * and we can just keep the helper alive without it needing to bootstrap
+        * communication.
+        *
+        * So we're trading efficiency for robustness. In this case, the checkins 
+        * should happen pretty infrequently, so it's pretty worth it.
+        */
+       if (_s_event_update_port != MACH_PORT_NULL) {
+               (void)job_assumes(j, launchd_mport_deallocate(_s_event_update_port) == KERN_SUCCESS);
+       }
+       _s_event_update_port = ping_port;
+       
+       kern_return_t result = BOOTSTRAP_NO_MEMORY;
+       launch_data_t arr = launch_data_alloc(LAUNCH_DATA_ARRAY);
+       if (job_assumes(j, arr != NULL)) {
+               struct eventsystem *es = eventsystem_find(name);
+               if (unlikely(es == NULL)) {
+                       es = eventsystem_new(name);
+               }
+               
+               if (job_assumes(j, es != NULL)) {
+                       struct externalevent *ei = NULL;
+                       size_t i = 0;
+                       LIST_FOREACH(ei, &es->events, sys_le) {
+                               (void)job_assumes(j, launch_data_array_set_index(arr, ei->event, i));
+                               if (job_assumes(j, i < 1024)) {
+                                       tokens[i] = ei->id;
+                               } else {
+                                       break;
+                               }
+                               i++;
+                       }
+                       
+                       /* Big enough. */
+                       *outvalCnt = 10 * 1024;
+                       mig_allocate(outval, *outvalCnt);
+                       
+                       size_t sz = launch_data_pack(arr, (void *)*outval, *outvalCnt, NULL, NULL);
+                       if (job_assumes(j, sz != 0)) {
+                               result = BOOTSTRAP_SUCCESS;
+                       } else {
+                               mig_deallocate(*outval, *outvalCnt);
+                       }
+               }
+
+               /* Total hack, but launch_data doesn't do ref-counting. */
+               struct _launch_data *hack = (struct _launch_data *)arr;
+               free(hack->_array);
+               free(arr);
+       }
+       
+       return result;
+}
 
 
+kern_return_t
+job_mig_event_set_state(job_t j, name_t name, uint64_t token, boolean_t state)
+{
+       if (!j->event_monitor) {
+               return BOOTSTRAP_NOT_PRIVILEGED;
+       }
+       
+       struct externalevent *ei = externalevent_find(name, token);
+       if (job_assumes(j, ei != NULL)) {
+               ei->state = state;
+               if(job_dispatch(ei->job, false) == NULL) {
+                       if (errno == EPERM) {
+                               return BOOTSTRAP_NOT_PRIVILEGED;
+                       }
+                       return BOOTSTRAP_NO_MEMORY;
+               }
+       } else {
+               return BOOTSTRAP_NO_MEMORY;
+       }
+       
        return BOOTSTRAP_SUCCESS;
 }
 
        return BOOTSTRAP_SUCCESS;
 }
 
@@ -8818,12 +10267,21 @@ jobmgr_init(bool sflag)
        LIST_INIT(&s_needing_sessions);
        
        launchd_assert((root_jobmgr = jobmgr_new(NULL, MACH_PORT_NULL, MACH_PORT_NULL, sflag, root_session_type, false, MACH_PORT_NULL)) != NULL);
        LIST_INIT(&s_needing_sessions);
        
        launchd_assert((root_jobmgr = jobmgr_new(NULL, MACH_PORT_NULL, MACH_PORT_NULL, sflag, root_session_type, false, MACH_PORT_NULL)) != NULL);
-       
+#ifndef __LAUNCH_DISABLE_XPC_SUPPORT__
+       launchd_assert((_s_xpc_system_domain = jobmgr_new_xpc_singleton_domain(root_jobmgr, "com.apple.xpc.system")) != NULL);
+       _s_xpc_system_domain->req_asid = g_audit_session;
+       _s_xpc_system_domain->req_asport = g_audit_session_port;
+       _s_xpc_system_domain->shortdesc = "system";
+#endif
+       if (pid1_magic) {
+               root_jobmgr->monitor_shutdown = true;
+       }
+
        uint32_t fflags = NOTE_ATTRIB | NOTE_LINK | NOTE_REVOKE | NOTE_EXTEND | NOTE_WRITE;
        s_no_hang_fd = open("/dev/autofs_nowait", O_EVTONLY | O_NONBLOCK);
        uint32_t fflags = NOTE_ATTRIB | NOTE_LINK | NOTE_REVOKE | NOTE_EXTEND | NOTE_WRITE;
        s_no_hang_fd = open("/dev/autofs_nowait", O_EVTONLY | O_NONBLOCK);
-       if( likely(s_no_hang_fd == -1) ) {
-               if( jobmgr_assumes(root_jobmgr, (s_no_hang_fd = open("/dev", O_EVTONLY | O_NONBLOCK)) != -1) ) {
-                       jobmgr_assumes(root_jobmgr, kevent_mod((uintptr_t)s_no_hang_fd, EVFILT_VNODE, EV_ADD, fflags, 0, root_jobmgr) != -1);
+       if (likely(s_no_hang_fd == -1)) {
+               if (jobmgr_assumes(root_jobmgr, (s_no_hang_fd = open("/dev", O_EVTONLY | O_NONBLOCK)) != -1)) {
+                       (void)jobmgr_assumes(root_jobmgr, kevent_mod((uintptr_t)s_no_hang_fd, EVFILT_VNODE, EV_ADD, fflags, 0, root_jobmgr) != -1);
                }
        }
        s_no_hang_fd = _fd(s_no_hang_fd);
                }
        }
        s_no_hang_fd = _fd(s_no_hang_fd);
@@ -8876,42 +10334,13 @@ waiting4removal_new(job_t j, mach_port_t rp)
 void
 waiting4removal_delete(job_t j, struct waiting_for_removal *w4r)
 {
 void
 waiting4removal_delete(job_t j, struct waiting_for_removal *w4r)
 {
-       job_assumes(j, job_mig_send_signal_reply(w4r->reply_port, 0) == 0);
+       (void)job_assumes(j, job_mig_send_signal_reply(w4r->reply_port, 0) == 0);
 
        SLIST_REMOVE(&j->removal_watchers, w4r, waiting_for_removal, sle);
 
        free(w4r);
 }
 
 
        SLIST_REMOVE(&j->removal_watchers, w4r, waiting_for_removal, sle);
 
        free(w4r);
 }
 
-bool 
-waiting4exit_new(job_t j, mach_port_t rp, bool legacy)
-{
-       struct waiting_for_exit *w4e = NULL;
-       if( !job_assumes(j, (w4e = malloc(sizeof(struct waiting_for_exit))) != NULL) ) {
-               return false;
-       }
-       
-       w4e->rp = rp;
-       w4e->legacy = legacy;
-       LIST_INSERT_HEAD(&j->exit_watchers, w4e, sle);
-       
-       return true;
-}
-
-void
-waiting4exit_delete(job_t j, struct waiting_for_exit *w4e)
-{
-       if( !w4e->legacy ) {
-               job_assumes(j, job_mig_wait2_reply(w4e->rp, KERN_SUCCESS, j->last_exit_status, false) == KERN_SUCCESS);
-       } else {
-               job_assumes(j, job_mig_wait_reply(w4e->rp, KERN_SUCCESS, j->last_exit_status) == KERN_SUCCESS);
-       }
-       
-       LIST_REMOVE(w4e, sle);
-       
-       free(w4e);
-}
-
 size_t
 get_kern_max_proc(void)
 {
 size_t
 get_kern_max_proc(void)
 {
@@ -8919,7 +10348,7 @@ get_kern_max_proc(void)
        int max = 100;
        size_t max_sz = sizeof(max);
        
        int max = 100;
        size_t max_sz = sizeof(max);
        
-       launchd_assumes(sysctl(mib, 2, &max, &max_sz, NULL, 0) != -1);
+       (void)launchd_assumes(sysctl(mib, 2, &max, &max_sz, NULL, 0) != -1);
        
        return max;
 }
        
        return max;
 }
@@ -8928,7 +10357,7 @@ get_kern_max_proc(void)
 void
 eliminate_double_reboot(void)
 {
 void
 eliminate_double_reboot(void)
 {
-       if( unlikely(!pid1_magic) ) {
+       if (unlikely(!pid1_magic)) {
                return;
        }
        
                return;
        }
        
@@ -8937,26 +10366,26 @@ eliminate_double_reboot(void)
        char *try_again = "Will try again at next boot.";
        int result = ~0;
        
        char *try_again = "Will try again at next boot.";
        int result = ~0;
        
-       if( unlikely(stat(argv[1], &sb) != -1) ) {
+       if (unlikely(stat(argv[1], &sb) != -1)) {
                jobmgr_log(root_jobmgr, LOG_DEBUG | LOG_CONSOLE, "Going to run deferred install script.");
                
                int wstatus;
                pid_t p;
                
                jobmgr_log(root_jobmgr, LOG_DEBUG | LOG_CONSOLE, "Going to run deferred install script.");
                
                int wstatus;
                pid_t p;
                
-               jobmgr_assumes(root_jobmgr, (errno = posix_spawnp(&p, argv[0], NULL, NULL, (char **)argv, environ)) == 0);
+               (void)jobmgr_assumes(root_jobmgr, (errno = posix_spawnp(&p, argv[0], NULL, NULL, (char **)argv, environ)) == 0);
                
                if (errno) {
                        jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Couldn't run deferred install script! %s", try_again);
                        goto out;
                }
                
                
                if (errno) {
                        jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Couldn't run deferred install script! %s", try_again);
                        goto out;
                }
                
-               if( !jobmgr_assumes(root_jobmgr, waitpid(p, &wstatus, 0) != -1) ) {
+               if (!jobmgr_assumes(root_jobmgr, waitpid(p, &wstatus, 0) != -1)) {
                        jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Couldn't confirm that deferred install script exited successfully! %s", try_again);
                        goto out;
                }
                
                        jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Couldn't confirm that deferred install script exited successfully! %s", try_again);
                        goto out;
                }
                
-               if( jobmgr_assumes(root_jobmgr, WIFEXITED(wstatus) != 0) ) {
-                       if( jobmgr_assumes(root_jobmgr, (result = WEXITSTATUS(wstatus)) == EXIT_SUCCESS) ) {
+               if (jobmgr_assumes(root_jobmgr, WIFEXITED(wstatus) != 0)) {
+                       if (jobmgr_assumes(root_jobmgr, (result = WEXITSTATUS(wstatus)) == EXIT_SUCCESS)) {
                                jobmgr_log(root_jobmgr, LOG_DEBUG | LOG_CONSOLE, "Deferred install script completed successfully.");
                        } else {
                                jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Deferred install script exited with status %d. %s", WEXITSTATUS(wstatus), try_again);
                                jobmgr_log(root_jobmgr, LOG_DEBUG | LOG_CONSOLE, "Deferred install script completed successfully.");
                        } else {
                                jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Deferred install script exited with status %d. %s", WEXITSTATUS(wstatus), try_again);
@@ -8966,42 +10395,33 @@ eliminate_double_reboot(void)
                }
        }
 out:
                }
        }
 out:
-       if( result == 0 ) {
+       if (result == 0) {
                /* If the unlink(2) was to fail, it would be most likely fail with EBUSY. All the other
                 * failure cases for unlink(2) don't apply when we're running under PID 1 and have verified
                 * that the file exists. Outside of someone deliberately messing with us (like if /etc/rc.deferredinstall
                 * is actually a looping sym-link or a mount point for a filesystem) and I/O errors, we should be good.
                 */
                /* If the unlink(2) was to fail, it would be most likely fail with EBUSY. All the other
                 * failure cases for unlink(2) don't apply when we're running under PID 1 and have verified
                 * that the file exists. Outside of someone deliberately messing with us (like if /etc/rc.deferredinstall
                 * is actually a looping sym-link or a mount point for a filesystem) and I/O errors, we should be good.
                 */
-               if( !jobmgr_assumes(root_jobmgr, unlink(argv[1]) != -1) ) {
+               if (!jobmgr_assumes(root_jobmgr, unlink(argv[1]) != -1)) {
                        jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Deferred install script couldn't be removed!");
                }
        }
 }
 
                        jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Deferred install script couldn't be removed!");
                }
        }
 }
 
-static void
-simulate_pid1_crash(void)
-{
-       if( pid1_magic && g_simulate_pid1_crash ) {
-               runtime_syslog(LOG_EMERG | LOG_CONSOLE, "About to simulate a crash.");
-               raise(SIGSEGV);
-       }
-}
-
 void
 jetsam_property_setup(launch_data_t obj, const char *key, job_t j)
 {
        job_log(j, LOG_DEBUG, "Setting Jetsam properties for job...");
 void
 jetsam_property_setup(launch_data_t obj, const char *key, job_t j)
 {
        job_log(j, LOG_DEBUG, "Setting Jetsam properties for job...");
-       if( strcasecmp(key, LAUNCH_JOBKEY_JETSAMPRIORITY) == 0 && launch_data_get_type(obj) == LAUNCH_DATA_INTEGER ) {
+       if (strcasecmp(key, LAUNCH_JOBKEY_JETSAMPRIORITY) == 0 && launch_data_get_type(obj) == LAUNCH_DATA_INTEGER) {
                j->jetsam_priority = (typeof(j->jetsam_priority))launch_data_get_integer(obj);
                job_log(j, LOG_DEBUG, "Priority: %d", j->jetsam_priority);
                j->jetsam_priority = (typeof(j->jetsam_priority))launch_data_get_integer(obj);
                job_log(j, LOG_DEBUG, "Priority: %d", j->jetsam_priority);
-       } else if( strcasecmp(key, LAUNCH_JOBKEY_JETSAMMEMORYLIMIT) == 0 && launch_data_get_type(obj) == LAUNCH_DATA_INTEGER ) {
+       } else if (strcasecmp(key, LAUNCH_JOBKEY_JETSAMMEMORYLIMIT) == 0 && launch_data_get_type(obj) == LAUNCH_DATA_INTEGER) {
                j->jetsam_memlimit = (typeof(j->jetsam_memlimit))launch_data_get_integer(obj);
                job_log(j, LOG_DEBUG, "Memory limit: %d", j->jetsam_memlimit);
                j->jetsam_memlimit = (typeof(j->jetsam_memlimit))launch_data_get_integer(obj);
                job_log(j, LOG_DEBUG, "Memory limit: %d", j->jetsam_memlimit);
-       } else if( strcasecmp(key, LAUNCH_KEY_JETSAMFRONTMOST) == 0 ) {
+       } else if (strcasecmp(key, LAUNCH_KEY_JETSAMFRONTMOST) == 0) {
                /* Ignore. We only recognize this key so we don't complain when we get SpringBoard's request. 
                 * You can't set this in a plist.
                 */
                /* Ignore. We only recognize this key so we don't complain when we get SpringBoard's request. 
                 * You can't set this in a plist.
                 */
-       } else if( strcasecmp(key, LAUNCH_KEY_JETSAMLABEL) == 0 ) {
+       } else if (strcasecmp(key, LAUNCH_KEY_JETSAMLABEL) == 0) {
                /* Ignore. This key is present in SpringBoard's request dictionary, so we don't want to
                 * complain about it.
                 */
                /* Ignore. This key is present in SpringBoard's request dictionary, so we don't want to
                 * complain about it.
                 */
@@ -9009,17 +10429,19 @@ jetsam_property_setup(launch_data_t obj, const char *key, job_t j)
                job_log(j, LOG_ERR, "Unknown Jetsam key: %s", key);
        }
        
                job_log(j, LOG_ERR, "Unknown Jetsam key: %s", key);
        }
        
-       if( unlikely(!j->jetsam_properties) ) {
+       if (unlikely(!j->jetsam_properties)) {
                j->jetsam_properties = true;
                LIST_INSERT_HEAD(&j->mgr->jetsam_jobs, j, jetsam_sle);
                j->mgr->jetsam_jobs_cnt++;
        }
                j->jetsam_properties = true;
                LIST_INSERT_HEAD(&j->mgr->jetsam_jobs, j, jetsam_sle);
                j->mgr->jetsam_jobs_cnt++;
        }
+
+       j->jetsam_seq = s_jetsam_sequence_id++;
 }
 
 int
 launchd_set_jetsam_priorities(launch_data_t priorities)
 {
 }
 
 int
 launchd_set_jetsam_priorities(launch_data_t priorities)
 {
-       if( !launchd_assumes(launch_data_get_type(priorities) == LAUNCH_DATA_ARRAY) ) {
+       if (!launchd_assumes(launch_data_get_type(priorities) == LAUNCH_DATA_ARRAY)) {
                return EINVAL;
        }
 
                return EINVAL;
        }
 
@@ -9027,14 +10449,14 @@ launchd_set_jetsam_priorities(launch_data_t priorities)
 #if !TARGET_OS_EMBEDDED
        /* For testing. */
        jm = jobmgr_find_by_name(root_jobmgr, VPROCMGR_SESSION_AQUA);
 #if !TARGET_OS_EMBEDDED
        /* For testing. */
        jm = jobmgr_find_by_name(root_jobmgr, VPROCMGR_SESSION_AQUA);
-       if( !launchd_assumes(jm != NULL) ) {
+       if (!launchd_assumes(jm != NULL)) {
                return EINVAL;
        }
 #else
        /* Since this is for embedded, we can assume that the root job manager holds the Jetsam jobs. */
        jm = root_jobmgr;
        
                return EINVAL;
        }
 #else
        /* Since this is for embedded, we can assume that the root job manager holds the Jetsam jobs. */
        jm = root_jobmgr;
        
-       if( !g_embedded_privileged_action ) {
+       if (!g_embedded_privileged_action) {
                return EPERM;
        }
 #endif
                return EPERM;
        }
 #endif
@@ -9043,36 +10465,36 @@ launchd_set_jetsam_priorities(launch_data_t priorities)
 
        job_t ji = NULL;
        size_t i = 0;
 
        job_t ji = NULL;
        size_t i = 0;
-       for( i = 0; i < npris; i++ ) {
+       for (i = 0; i < npris; i++) {
                launch_data_t ldi = launch_data_array_get_index(priorities, i);
                launch_data_t ldi = launch_data_array_get_index(priorities, i);
-               if( !launchd_assumes(launch_data_get_type(ldi) == LAUNCH_DATA_DICTIONARY) ) {
+               if (!launchd_assumes(launch_data_get_type(ldi) == LAUNCH_DATA_DICTIONARY)) {
                        continue;
                }
                
                launch_data_t label = NULL;
                        continue;
                }
                
                launch_data_t label = NULL;
-               if( !launchd_assumes(label = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMLABEL)) ) {
+               if (!launchd_assumes(label = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMLABEL))) {
                        continue;
                }
                const char *_label = launch_data_get_string(label);
                
                        continue;
                }
                const char *_label = launch_data_get_string(label);
                
-               ji = job_find(_label);
-               if( !launchd_assumes(ji != NULL) ) {
+               ji = job_find(NULL, _label);
+               if (!launchd_assumes(ji != NULL)) {
                        continue;
                }
 
                launch_data_dict_iterate(ldi, (void (*)(launch_data_t, const char *, void *))jetsam_property_setup, ji);
 
                launch_data_t frontmost = NULL;
                        continue;
                }
 
                launch_data_dict_iterate(ldi, (void (*)(launch_data_t, const char *, void *))jetsam_property_setup, ji);
 
                launch_data_t frontmost = NULL;
-               if( (frontmost = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMFRONTMOST)) && launch_data_get_type(frontmost) == LAUNCH_DATA_BOOL ) {
+               if ((frontmost = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMFRONTMOST)) && launch_data_get_type(frontmost) == LAUNCH_DATA_BOOL) {
                        ji->jetsam_frontmost = launch_data_get_bool(frontmost);
                }
        }
        
        i = 0;
        job_t *jobs = (job_t *)calloc(jm->jetsam_jobs_cnt, sizeof(job_t));
                        ji->jetsam_frontmost = launch_data_get_bool(frontmost);
                }
        }
        
        i = 0;
        job_t *jobs = (job_t *)calloc(jm->jetsam_jobs_cnt, sizeof(job_t));
-       if( launchd_assumes(jobs != NULL) ) {
-               LIST_FOREACH( ji, &jm->jetsam_jobs, jetsam_sle ) {
-                       if( ji->p ) {
+       if (launchd_assumes(jobs != NULL)) {
+               LIST_FOREACH(ji, &jm->jetsam_jobs, jetsam_sle) {
+                       if (ji->p) {
                                jobs[i] = ji;
                                i++;
                        }
                                jobs[i] = ji;
                                i++;
                        }
@@ -9084,39 +10506,45 @@ launchd_set_jetsam_priorities(launch_data_t priorities)
        int result = EINVAL;
        
        /* It is conceivable that there could be no Jetsam jobs running. */
        int result = EINVAL;
        
        /* It is conceivable that there could be no Jetsam jobs running. */
-       if( totalpris > 0 ) {
+       if (totalpris > 0) {
                /* Yay blocks! */
                qsort_b((void *)jobs, totalpris, sizeof(job_t), ^ int (const void *lhs, const void *rhs) {
                        job_t _lhs = *(job_t *)lhs;
                        job_t _rhs = *(job_t *)rhs;
                        /* Sort in descending order. (Priority correlates to the soonishness with which you will be killed.) */
                /* Yay blocks! */
                qsort_b((void *)jobs, totalpris, sizeof(job_t), ^ int (const void *lhs, const void *rhs) {
                        job_t _lhs = *(job_t *)lhs;
                        job_t _rhs = *(job_t *)rhs;
                        /* Sort in descending order. (Priority correlates to the soonishness with which you will be killed.) */
-                       if( _lhs->jetsam_priority > _rhs->jetsam_priority ) {
+                       if (_lhs->jetsam_priority > _rhs->jetsam_priority) {
                                return -1;
                                return -1;
-                       } else if( _lhs->jetsam_priority < _rhs->jetsam_priority ) {
+                       } else if (_lhs->jetsam_priority < _rhs->jetsam_priority) {
                                return 1;
                        }
                                return 1;
                        }
+                       /* Priority is equal, so sort by sequence ID to maintain LRU order */
+                       if( (int)(_lhs->jetsam_seq - _rhs->jetsam_seq) > 0 ) {
+                               return 1;
+                       } else if( (int)(_lhs->jetsam_seq - _rhs->jetsam_seq) < 0 ) {
+                               return -1;
+                       }
                        
                        return 0;
                });
                
                jetsam_priority_entry_t *jpris = (jetsam_priority_entry_t *)calloc(totalpris, sizeof(jetsam_priority_entry_t));
                        
                        return 0;
                });
                
                jetsam_priority_entry_t *jpris = (jetsam_priority_entry_t *)calloc(totalpris, sizeof(jetsam_priority_entry_t));
-               if( !launchd_assumes(jpris != NULL) ) {
+               if (!launchd_assumes(jpris != NULL)) {
                        result = ENOMEM;
                } else {
                        result = ENOMEM;
                } else {
-                       for( i = 0; i < totalpris; i++ ) {
+                       for (i = 0; i < totalpris; i++) {
                                jpris[i].pid = jobs[i]->p; /* Subject to time-of-use vs. time-of-check, obviously. */
                                jpris[i].flags |= jobs[i]->jetsam_frontmost ? kJetsamFlagsFrontmost : 0;
                                jpris[i].hiwat_pages = jobs[i]->jetsam_memlimit;
                        }
                        
                                jpris[i].pid = jobs[i]->p; /* Subject to time-of-use vs. time-of-check, obviously. */
                                jpris[i].flags |= jobs[i]->jetsam_frontmost ? kJetsamFlagsFrontmost : 0;
                                jpris[i].hiwat_pages = jobs[i]->jetsam_memlimit;
                        }
                        
-                       launchd_assumes((result = sysctlbyname("kern.memorystatus_priority_list", NULL, NULL, &jpris[0], totalpris * sizeof(jetsam_priority_entry_t))) != -1);
+                       (void)launchd_assumes((result = sysctlbyname("kern.memorystatus_priority_list", NULL, NULL, &jpris[0], totalpris * sizeof(jetsam_priority_entry_t))) != -1);
                        result = result != 0 ? errno : 0;
                        
                        free(jpris);
                }
        }
        
                        result = result != 0 ? errno : 0;
                        
                        free(jpris);
                }
        }
        
-       if( jobs ) {
+       if (jobs) {
                free(jobs);
        }
        
                free(jobs);
        }
        
index 3cc6e3720f5b3a366270b47a36b0589e103610d0..0c812460b32bf773b465a55e9e7a2ea2416aa4e3 100644 (file)
@@ -43,7 +43,7 @@ jobmgr_t jobmgr_delete_anything_with_port(jobmgr_t jm, mach_port_t port);
 launch_data_t job_export_all(void);
 
 job_t job_dispatch(job_t j, bool kickstart); /* returns j on success, NULL on job removal */
 launch_data_t job_export_all(void);
 
 job_t job_dispatch(job_t j, bool kickstart); /* returns j on success, NULL on job removal */
-job_t job_find(const char *label);
+job_t job_find(jobmgr_t jm, const char *label);
 job_t job_find_by_service_port(mach_port_t p);
 bool job_ack_port_destruction(mach_port_t p);
 bool job_is_anonymous(job_t j);
 job_t job_find_by_service_port(mach_port_t p);
 bool job_ack_port_destruction(mach_port_t p);
 bool job_is_anonymous(job_t j);
diff --git a/launchd/src/launchd_helper.defs b/launchd/src/launchd_helper.defs
new file mode 100644 (file)
index 0000000..bf69105
--- /dev/null
@@ -0,0 +1,24 @@
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+#include "launchd_mig_types.defs"
+import "vproc.h";
+import "vproc_priv.h";
+import "vproc_internal.h";
+
+subsystem launchd_helper 4241011;
+
+userprefix helper_downcall_;
+serverprefix helper_recv_;
+
+simpleroutine
+ping(
+                                       p                       : mach_port_move_send_once_t;
+ServerAuditToken       token           : audit_token_t
+);
+
+/* For coreservicesd to harvest exit status, not actually for UserEventAgent. */
+simpleroutine
+wait(
+                                       p                       : mach_port_move_send_once_t;
+                                       status          : int
+);
index 082ff0b472b325cf773f78373c015e4564b2afcb..99a16618511e4f6828a2875a3cdd7eab3e02ba67 100644 (file)
@@ -25,6 +25,8 @@ subsystem launchd_internal 137000;
 
 serverprefix x_;
 
 
 serverprefix x_;
 
-routine handle_kqueue(
-                                               __port  : mach_port_t;
-                                               __fd    : integer_t);
+routine
+handle_kqueue(
+       p       : mach_port_t;
+       fd      : integer_t
+);
index 5e21c5a23520236ed0cf5e1170b685e5a9292577..a8eab4f6d11adc9079504e7a71055b3a7238a308 100644 (file)
@@ -34,4 +34,4 @@ void runtime_ktrace1(runtime_ktrace_code_t code);
 void runtime_ktrace0(runtime_ktrace_code_t code);
 void runtime_ktrace(runtime_ktrace_code_t code, long a, long b, long c);
 
 void runtime_ktrace0(runtime_ktrace_code_t code);
 void runtime_ktrace(runtime_ktrace_code_t code, long a, long b, long c);
 
-#endif /* __LAUNCHD_KTRACE_H__ */
+#endif
index 02eabb69d09ce9e221740c6576893e1d2ea68e13..46880114ef518ce6f783820240fe418a562aaa29 100644 (file)
@@ -37,6 +37,7 @@ type bootstrap_property_array_t       = ^array [] of bootstrap_property_t;
 type bootstrap_status_t                        = integer_t;
 type bootstrap_status_array_t  = ^array [] of bootstrap_status_t;
 type uuid_t                                            = array [16] of MACH_MSG_TYPE_BYTE;
 type bootstrap_status_t                        = integer_t;
 type bootstrap_status_array_t  = ^array [] of bootstrap_status_t;
 type uuid_t                                            = array [16] of MACH_MSG_TYPE_BYTE;
+type event_token_array_t               = array [1024] of uint64_t;
 
 type job_t = mach_port_t
         intran         : job_t job_mig_intran(mach_port_t) 
 
 type job_t = mach_port_t
         intran         : job_t job_mig_intran(mach_port_t) 
index 60d6db06d03e808cd79054938a70295e9376f397..ac0e712ca7e20b9ddf29416f67de80a7a9d3519a 100644 (file)
@@ -18,7 +18,7 @@
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
-static const char *const __rcs_file_version__ = "$Revision: 24003 $";
+static const char *const __rcs_file_version__ = "$Revision: 24912 $";
 
 #include "config.h"
 #include "launchd_runtime.h"
 
 #include "config.h"
 #include "launchd_runtime.h"
@@ -73,8 +73,14 @@ static const char *const __rcs_file_version__ = "$Revision: 24003 $";
 #include "vproc.h"
 #include "vproc_priv.h"
 #include "vproc_internal.h"
 #include "vproc.h"
 #include "vproc_priv.h"
 #include "vproc_internal.h"
+#include "protocol_vprocServer.h"
 #include "protocol_job_reply.h"
 
 #include "protocol_job_reply.h"
 
+#if !TARGET_OS_EMBEDDED
+#include "domainServer.h"
+#endif
+#include "eventsServer.h"
+
 static mach_port_t ipc_port_set;
 static mach_port_t demand_port_set;
 static mach_port_t launchd_internal_port;
 static mach_port_t ipc_port_set;
 static mach_port_t demand_port_set;
 static mach_port_t launchd_internal_port;
@@ -127,9 +133,9 @@ static FILE *ourlogfile;
 bool pid1_magic;
 bool do_apple_internal_logging;
 bool low_level_debug;
 bool pid1_magic;
 bool do_apple_internal_logging;
 bool low_level_debug;
-bool g_force_old_kill_path = false;
 bool g_flat_mach_namespace = true;
 bool g_simulate_pid1_crash = false;
 bool g_flat_mach_namespace = true;
 bool g_simulate_pid1_crash = false;
+bool g_malloc_log_stacks = false;
 bool g_use_gmalloc = false;
 bool g_log_per_user_shutdown = false;
 #if !TARGET_OS_EMBEDDED
 bool g_use_gmalloc = false;
 bool g_log_per_user_shutdown = false;
 #if !TARGET_OS_EMBEDDED
@@ -138,6 +144,7 @@ bool g_log_pid1_shutdown = true;
 bool g_log_pid1_shutdown = false;
 #endif
 bool g_log_strict_usage = false;
 bool g_log_pid1_shutdown = false;
 #endif
 bool g_log_strict_usage = false;
+bool g_trap_sigkill_bugs = false;
 pid_t g_wsp = 0;
 size_t runtime_busy_cnt;
 
 pid_t g_wsp = 0;
 size_t runtime_busy_cnt;
 
@@ -178,7 +185,7 @@ launchd_runtime_init(void)
        launchd_assert(pthread_create(&kqueue_demand_thread, NULL, kqueue_demand_loop, NULL) == 0);
        launchd_assert(pthread_detach(kqueue_demand_thread) == 0);
 
        launchd_assert(pthread_create(&kqueue_demand_thread, NULL, kqueue_demand_loop, NULL) == 0);
        launchd_assert(pthread_detach(kqueue_demand_thread) == 0);
 
-       launchd_assumes(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)) != -1);
+       (void)launchd_assumes(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)) != -1);
 }
 
 void
 }
 
 void
@@ -188,74 +195,11 @@ launchd_runtime_init2(void)
 
        for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
                sigaddset(&sigign_set, sigigns[i]);
 
        for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
                sigaddset(&sigign_set, sigigns[i]);
-               launchd_assumes(signal(sigigns[i], SIG_IGN) != SIG_ERR);
+               (void)launchd_assumes(signal(sigigns[i], SIG_IGN) != SIG_ERR);
        }
 }
 
        }
 }
 
-const char *
-proc_flags_to_C_names(unsigned int flags)
-{
-#define MAX_PFLAG_STR "P_ADVLOCK|P_CONTROLT|P_LP64|P_NOCLDSTOP|P_PPWAIT|P_PROFIL|P_SELECT|P_CONTINUED|P_SUGID|P_SYSTEM|P_TIMEOUT|P_TRACED|P_RESV3|P_WEXIT|P_EXEC|P_OWEUPC|P_AFFINITY|P_TRANSLATED|P_RESV5|P_CHECKOPENEVT|P_DEPENDENCY_CAPABLE|P_REBOOT|P_TBE|P_RESV7|P_THCWD|P_RESV9|P_RESV10|P_RESV11|P_NOSHLIB|P_FORCEQUOTA|P_NOCLDWAIT|P_NOREMOTEHANG|0xdeadbeeffeedface"
-
-       static char flags_buf[sizeof(MAX_PFLAG_STR)];
-       char *flags_off = NULL;
-
-       if (!flags) {
-               return "";
-       }
-
-       while (flags) {
-               if (flags_off) {
-                       *flags_off = '|';
-                       flags_off++;
-                       *flags_off = '\0';
-               } else {
-                       flags_off = flags_buf;
-               }
-
 #define FLAGIF(f) if (flags & f) { flags_off += sprintf(flags_off, #f); flags &= ~f; }
 #define FLAGIF(f) if (flags & f) { flags_off += sprintf(flags_off, #f); flags &= ~f; }
-
-               FLAGIF(P_ADVLOCK)
-               else FLAGIF(P_CONTROLT)
-               else FLAGIF(P_LP64)
-               else FLAGIF(P_NOCLDSTOP)
-               else FLAGIF(P_PPWAIT)
-               else FLAGIF(P_PROFIL)
-               else FLAGIF(P_SELECT)
-               else FLAGIF(P_CONTINUED)
-               else FLAGIF(P_SUGID)
-               else FLAGIF(P_SYSTEM)
-               else FLAGIF(P_TIMEOUT)
-               else FLAGIF(P_TRACED)
-               else FLAGIF(P_RESV3)
-               else FLAGIF(P_WEXIT)
-               else FLAGIF(P_EXEC)
-               else FLAGIF(P_OWEUPC)
-               else FLAGIF(P_AFFINITY)
-               else FLAGIF(P_TRANSLATED)
-               else FLAGIF(P_RESV5)
-               else FLAGIF(P_CHECKOPENEVT)
-               else FLAGIF(P_DEPENDENCY_CAPABLE)
-               else FLAGIF(P_REBOOT)
-               else FLAGIF(P_TBE)
-               else FLAGIF(P_RESV7)
-               else FLAGIF(P_THCWD)
-               else FLAGIF(P_RESV9)
-               else FLAGIF(P_RESV10)
-               else FLAGIF(P_RESV11)
-               else FLAGIF(P_NOSHLIB)
-               else FLAGIF(P_FORCEQUOTA)
-               else FLAGIF(P_NOCLDWAIT)
-               else FLAGIF(P_NOREMOTEHANG)
-               else {
-                       flags_off += sprintf(flags_off, "0x%x", flags);
-                       flags = 0;
-               }
-       }
-
-       return flags_buf;
-}
-
 const char *
 reboot_flags_to_C_names(unsigned int flags)
 {
 const char *
 reboot_flags_to_C_names(unsigned int flags)
 {
@@ -549,7 +493,7 @@ mportset_callback(void)
                }
        }
 
                }
        }
 
-       launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)members,
+       (void)launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)members,
                                (vm_size_t) membersCnt * sizeof(mach_port_name_t)) == KERN_SUCCESS);
 }
 
                                (vm_size_t) membersCnt * sizeof(mach_port_name_t)) == KERN_SUCCESS);
 }
 
@@ -570,7 +514,7 @@ kqueue_demand_loop(void *arg __attribute__((unused)))
                FD_ZERO(&rfds);
                FD_SET(mainkq, &rfds);
                if (launchd_assumes(select(mainkq + 1, &rfds, NULL, NULL, NULL) == 1)) {
                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);
+                       (void)launchd_assumes(handle_kqueue(launchd_internal_port, mainkq) == 0);
                }
        }
 
                }
        }
 
@@ -587,11 +531,11 @@ x_handle_kqueue(mach_port_t junk __attribute__((unused)), integer_t fd)
        bulk_kev = kev;
 
        if (launchd_assumes((bulk_kev_cnt = kevent(fd, NULL, 0, kev, BULK_KEV_MAX, &ts)) != -1)) {
        bulk_kev = kev;
 
        if (launchd_assumes((bulk_kev_cnt = kevent(fd, NULL, 0, kev, BULK_KEV_MAX, &ts)) != -1)) {
-       #if 0   
+#if 0  
                for (i = 0; i < bulk_kev_cnt; i++) {
                        log_kevent_struct(LOG_DEBUG, &kev[0], i);
                }
                for (i = 0; i < bulk_kev_cnt; i++) {
                        log_kevent_struct(LOG_DEBUG, &kev[0], i);
                }
-       #endif
+#endif
                for (i = 0; i < bulk_kev_cnt; i++) {
                        bulk_kev_i = i;
                        kevi = &kev[i];
                for (i = 0; i < bulk_kev_cnt; i++) {
                        bulk_kev_i = i;
                        kevi = &kev[i];
@@ -599,7 +543,7 @@ x_handle_kqueue(mach_port_t junk __attribute__((unused)), integer_t fd)
                        if (kevi->filter) {
                                runtime_syslog(LOG_DEBUG, "Dispatching kevent...");
                                log_kevent_struct(LOG_DEBUG, kev, i);
                        if (kevi->filter) {
                                runtime_syslog(LOG_DEBUG, "Dispatching kevent...");
                                log_kevent_struct(LOG_DEBUG, kev, i);
-                       #if 0
+#if 0
                                /* Check if kevi->udata was either malloc(3)ed or is a valid function pointer. 
                                 * If neither, it's probably an invalid pointer and we should log it. 
                                 */
                                /* Check if kevi->udata was either malloc(3)ed or is a valid function pointer. 
                                 * If neither, it's probably an invalid pointer and we should log it. 
                                 */
@@ -612,11 +556,11 @@ x_handle_kqueue(mach_port_t junk __attribute__((unused)), integer_t fd)
                                        runtime_syslog(LOG_ERR, "The following kevent had invalid context data.");
                                        log_kevent_struct(LOG_EMERG, &kev[0], i);
                                }
                                        runtime_syslog(LOG_ERR, "The following kevent had invalid context data.");
                                        log_kevent_struct(LOG_EMERG, &kev[0], i);
                                }
-                       #else
+#else
                                runtime_ktrace(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_START, kevi->ident, kevi->filter, kevi->fflags);
                                (*((kq_callback *)kevi->udata))(kevi->udata, kevi);
                                runtime_ktrace0(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_END);
                                runtime_ktrace(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_START, kevi->ident, kevi->filter, kevi->fflags);
                                (*((kq_callback *)kevi->udata))(kevi->udata, kevi);
                                runtime_ktrace0(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_END);
-                       #endif
+#endif
                        }
                }
        }
                        }
                }
        }
@@ -635,11 +579,11 @@ launchd_runtime(void)
 
        for (;;) {
                if (likely(req)) {
 
        for (;;) {
                if (likely(req)) {
-                       launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)req, mz) == KERN_SUCCESS);
+                       (void)launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)req, mz) == KERN_SUCCESS);
                        req = NULL;
                }
                if (likely(resp)) {
                        req = NULL;
                }
                if (likely(resp)) {
-                       launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)resp, mz) == KERN_SUCCESS);
+                       (void)launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)resp, mz) == KERN_SUCCESS);
                        resp = NULL;
                }
 
                        resp = NULL;
                }
 
@@ -688,7 +632,7 @@ launchd_mport_notify_req(mach_port_t name, mach_msg_id_t which)
                        MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous);
 
        if (likely(errno == 0) && previous != MACH_PORT_NULL) {
                        MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous);
 
        if (likely(errno == 0) && previous != MACH_PORT_NULL) {
-               launchd_assumes(launchd_mport_deallocate(previous) == KERN_SUCCESS);
+               (void)launchd_assumes(launchd_mport_deallocate(previous) == KERN_SUCCESS);
        }
 
        return errno;
        }
 
        return errno;
@@ -704,13 +648,13 @@ runtime_fork(mach_port_t bsport)
 
        sigemptyset(&emptyset);
 
 
        sigemptyset(&emptyset);
 
-       launchd_assumes(launchd_mport_make_send(bsport) == KERN_SUCCESS);
-       launchd_assumes(launchd_set_bport(bsport) == KERN_SUCCESS);
-       launchd_assumes(launchd_mport_deallocate(bsport) == KERN_SUCCESS);
+       (void)launchd_assumes(launchd_mport_make_send(bsport) == KERN_SUCCESS);
+       (void)launchd_assumes(launchd_set_bport(bsport) == KERN_SUCCESS);
+       (void)launchd_assumes(launchd_mport_deallocate(bsport) == KERN_SUCCESS);
 
 
-       launchd_assumes(sigprocmask(SIG_BLOCK, &sigign_set, &oset) != -1);
+       (void)launchd_assumes(sigprocmask(SIG_BLOCK, &sigign_set, &oset) != -1);
        for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
        for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
-               launchd_assumes(signal(sigigns[i], SIG_DFL) != SIG_ERR);
+               (void)launchd_assumes(signal(sigigns[i], SIG_DFL) != SIG_ERR);
        }
 
        r = fork();
        }
 
        r = fork();
@@ -718,15 +662,15 @@ runtime_fork(mach_port_t bsport)
 
        if (r != 0) {
                for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
 
        if (r != 0) {
                for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
-                       launchd_assumes(signal(sigigns[i], SIG_IGN) != SIG_ERR);
+                       (void)launchd_assumes(signal(sigigns[i], SIG_IGN) != SIG_ERR);
                }
                }
-               launchd_assumes(sigprocmask(SIG_SETMASK, &oset, NULL) != -1);
-               launchd_assumes(launchd_set_bport(MACH_PORT_NULL) == KERN_SUCCESS);
+               (void)launchd_assumes(sigprocmask(SIG_SETMASK, &oset, NULL) != -1);
+               (void)launchd_assumes(launchd_set_bport(MACH_PORT_NULL) == KERN_SUCCESS);
        } else {
                pid_t p = -getpid();
        } else {
                pid_t p = -getpid();
-               launchd_assumes(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)) != -1);
+               (void)launchd_assumes(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)) != -1);
 
 
-               launchd_assumes(sigprocmask(SIG_SETMASK, &emptyset, NULL) != -1);
+               (void)launchd_assumes(sigprocmask(SIG_SETMASK, &emptyset, NULL) != -1);
        }
 
        errno = saved_errno;
        }
 
        errno = saved_errno;
@@ -801,6 +745,13 @@ launchd_mport_copy_send(mach_port_t name)
        return errno = mach_port_insert_right(mach_task_self(), name, name, MACH_MSG_TYPE_COPY_SEND);
 }
 
        return errno = mach_port_insert_right(mach_task_self(), name, name, MACH_MSG_TYPE_COPY_SEND);
 }
 
+kern_return_t
+launchd_mport_make_send_once(mach_port_t name, mach_port_t *so)
+{
+       mach_msg_type_name_t right = 0;
+       return errno = mach_port_extract_right(mach_task_self(), name, MACH_MSG_TYPE_MAKE_SEND_ONCE, so, &right);
+}
+
 kern_return_t
 launchd_mport_close_recv(mach_port_t name)
 {
 kern_return_t
 launchd_mport_close_recv(mach_port_t name)
 {
@@ -857,10 +808,10 @@ kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t
        if (flags & EV_ADD && !launchd_assumes(udata != NULL)) {
                errno = EINVAL;
                return -1;
        if (flags & EV_ADD && !launchd_assumes(udata != NULL)) {
                errno = EINVAL;
                return -1;
-       } else if( (flags & EV_DELETE) && bulk_kev ) {
+       } else if ((flags & EV_DELETE) && bulk_kev) {
                int i = 0;
                int i = 0;
-               for( i = bulk_kev_i + 1; i < bulk_kev_cnt; i++ ) {
-                       if( bulk_kev[i].filter == filter && bulk_kev[i].ident == ident ) {
+               for (i = bulk_kev_i + 1; i < bulk_kev_cnt; i++) {
+                       if (bulk_kev[i].filter == filter && bulk_kev[i].ident == ident) {
                                runtime_syslog(LOG_DEBUG, "Pruning the following kevent:");
                                log_kevent_struct(LOG_DEBUG, &bulk_kev[0], i);
                                bulk_kev[i].filter = (short)0;
                                runtime_syslog(LOG_DEBUG, "Pruning the following kevent:");
                                log_kevent_struct(LOG_DEBUG, &bulk_kev[0], i);
                                bulk_kev[i].filter = (short)0;
@@ -906,7 +857,7 @@ do_mach_notify_port_destroyed(mach_port_t notify __attribute__((unused)), mach_p
        /* This message is sent to us when a receive right is returned to us. */
 
        if (!launchd_assumes(job_ack_port_destruction(rights))) {
        /* This message is sent to us when a receive right is returned to us. */
 
        if (!launchd_assumes(job_ack_port_destruction(rights))) {
-               launchd_assumes(launchd_mport_close_recv(rights) == KERN_SUCCESS);
+               (void)launchd_assumes(launchd_mport_close_recv(rights) == KERN_SUCCESS);
        }
 
        return KERN_SUCCESS;
        }
 
        return KERN_SUCCESS;
@@ -960,7 +911,7 @@ do_mach_notify_dead_name(mach_port_t notify __attribute__((unused)), mach_port_n
         */
 
        if (name == drain_reply_port) {
         */
 
        if (name == drain_reply_port) {
-               launchd_assumes(launchd_mport_deallocate(name) == KERN_SUCCESS);
+               (void)launchd_assumes(launchd_mport_deallocate(name) == KERN_SUCCESS);
                drain_reply_port = MACH_PORT_NULL;
        }
 
                drain_reply_port = MACH_PORT_NULL;
        }
 
@@ -972,7 +923,7 @@ do_mach_notify_dead_name(mach_port_t notify __attribute__((unused)), mach_port_n
         * rights on said port. Let's deallocate it so that we don't leak
         * dead-name ports.
         */
         * rights on said port. Let's deallocate it so that we don't leak
         * dead-name ports.
         */
-       launchd_assumes(launchd_mport_deallocate(name) == KERN_SUCCESS);
+       (void)launchd_assumes(launchd_mport_deallocate(name) == KERN_SUCCESS);
 
        return KERN_SUCCESS;
 }
 
        return KERN_SUCCESS;
 }
@@ -990,7 +941,7 @@ record_caller_creds(mach_msg_header_t *mh)
        if (launchd_assumes(trailer_size >= (mach_msg_size_t)sizeof(audit_token_t))) {
                audit_token_to_au32(tp->msgh_audit, /* audit UID */ NULL, &ldc.euid,
                                &ldc.egid, &ldc.uid, &ldc.gid, &ldc.pid,
        if (launchd_assumes(trailer_size >= (mach_msg_size_t)sizeof(audit_token_t))) {
                audit_token_to_au32(tp->msgh_audit, /* audit UID */ NULL, &ldc.euid,
                                &ldc.egid, &ldc.uid, &ldc.gid, &ldc.pid,
-                               /* au_asid_t */ NULL, /* au_tid_t */ NULL);
+                               &ldc.asid, /* au_tid_t */ NULL);
        }
 
 }
        }
 
 }
@@ -1012,7 +963,7 @@ launchd_exc_runtime_once(mach_port_t port, mach_msg_size_t rcv_msg_size, mach_ms
                                
        do {
                mr = mach_msg(&bufRequest->Head, rcv_options, 0, rcv_msg_size, port, to, MACH_PORT_NULL);
                                
        do {
                mr = mach_msg(&bufRequest->Head, rcv_options, 0, rcv_msg_size, port, to, MACH_PORT_NULL);
-               switch( mr ) {
+               switch (mr) {
                        case MACH_RCV_TIMED_OUT :
                                runtime_syslog(LOG_DEBUG, "Message queue is empty.");
                                break;
                        case MACH_RCV_TIMED_OUT :
                                runtime_syslog(LOG_DEBUG, "Message queue is empty.");
                                break;
@@ -1020,11 +971,11 @@ launchd_exc_runtime_once(mach_port_t port, mach_msg_size_t rcv_msg_size, mach_ms
                                runtime_syslog(LOG_INFO, "Message is larger than %u bytes.", rcv_msg_size);
                                break;
                        default                                 :
                                runtime_syslog(LOG_INFO, "Message is larger than %u bytes.", rcv_msg_size);
                                break;
                        default                                 :
-                               launchd_assumes(mr == MACH_MSG_SUCCESS);
+                               (void)launchd_assumes(mr == MACH_MSG_SUCCESS);
                }
                
                }
                
-               if( mr == MACH_MSG_SUCCESS ) {
-                       if( !launchd_assumes(mach_exc_server(&bufRequest->Head, &bufReply->Head) == TRUE) ) {
+               if (mr == MACH_MSG_SUCCESS) {
+                       if (!launchd_assumes(mach_exc_server(&bufRequest->Head, &bufReply->Head) == TRUE)) {
                                runtime_syslog(LOG_WARNING, "Exception server routine failed.");
                                break;
                        }
                                runtime_syslog(LOG_WARNING, "Exception server routine failed.");
                                break;
                        }
@@ -1033,9 +984,9 @@ launchd_exc_runtime_once(mach_port_t port, mach_msg_size_t rcv_msg_size, mach_ms
                        mach_msg_option_t send_options =        MACH_SEND_MSG           |
                                                                                                MACH_SEND_TIMEOUT       ;
                        
                        mach_msg_option_t send_options =        MACH_SEND_MSG           |
                                                                                                MACH_SEND_TIMEOUT       ;
                        
-                       launchd_assumes(bufReply->Head.msgh_size <= send_msg_size);
+                       (void)launchd_assumes(bufReply->Head.msgh_size <= send_msg_size);
                        smr = mach_msg(&bufReply->Head, send_options, bufReply->Head.msgh_size, 0, MACH_PORT_NULL, to + 100, MACH_PORT_NULL);
                        smr = mach_msg(&bufReply->Head, send_options, bufReply->Head.msgh_size, 0, MACH_PORT_NULL, to + 100, MACH_PORT_NULL);
-                       switch( smr ) {
+                       switch (smr) {
                                case MACH_SEND_TIMED_OUT        :
                                        runtime_syslog(LOG_WARNING, "Timed out while trying to send reply to exception message.");
                                        break;
                                case MACH_SEND_TIMED_OUT        :
                                        runtime_syslog(LOG_WARNING, "Timed out while trying to send reply to exception message.");
                                        break;
@@ -1043,13 +994,13 @@ launchd_exc_runtime_once(mach_port_t port, mach_msg_size_t rcv_msg_size, mach_ms
                                        runtime_syslog(LOG_WARNING, "Tried sending a message to a port that we don't possess a send right to.");
                                        break;
                                default                                         :
                                        runtime_syslog(LOG_WARNING, "Tried sending a message to a port that we don't possess a send right to.");
                                        break;
                                default                                         :
-                                       if( !launchd_assumes(smr == MACH_MSG_SUCCESS) ) {
+                                       if (!launchd_assumes(smr == MACH_MSG_SUCCESS)) {
                                                runtime_syslog(LOG_WARNING, "Couldn't deliver exception reply: 0x%x", smr);
                                        }
                                        break;
                        }
                }
                                                runtime_syslog(LOG_WARNING, "Couldn't deliver exception reply: 0x%x", smr);
                                        }
                                        break;
                        }
                }
-       } while( 0 );
+       } while (0);
        
        return mr;
 }
        
        return mr;
 }
@@ -1086,11 +1037,11 @@ launchd_runtime2(mach_msg_size_t msg_size, mig_reply_error_t *bufRequest, mig_re
                        tmp_options |= MACH_RCV_TIMEOUT;
 
                        if (!(tmp_options & MACH_SEND_TIMEOUT)) {
                        tmp_options |= MACH_RCV_TIMEOUT;
 
                        if (!(tmp_options & MACH_SEND_TIMEOUT)) {
-                       #if !TARGET_OS_EMBEDDED
+#if !TARGET_OS_EMBEDDED
                                to = busy_cnt ? runtime_idle_timeout : (_vproc_standby_timeout() * 1000);
                                to = busy_cnt ? runtime_idle_timeout : (_vproc_standby_timeout() * 1000);
-                       #else
+#else
                                to = runtime_idle_timeout;
                                to = runtime_idle_timeout;
-                       #endif
+#endif
                        }
                }
 
                        }
                }
 
@@ -1123,7 +1074,7 @@ launchd_runtime2(mach_msg_size_t msg_size, mig_reply_error_t *bufRequest, mig_re
                        }
                        continue;
                default:
                        }
                        continue;
                default:
-                       if( !launchd_assumes(mr == MACH_MSG_SUCCESS) ) {
+                       if (!launchd_assumes(mr == MACH_MSG_SUCCESS)) {
                                runtime_syslog(LOG_ERR, "mach_msg(): %u: %s", mr, mach_error_string(mr));
                        }
                        continue;
                                runtime_syslog(LOG_ERR, "mach_msg(): %u: %s", mr, mach_error_string(mr));
                        }
                        continue;
@@ -1159,6 +1110,16 @@ launchd_runtime2(mach_msg_size_t msg_size, mig_reply_error_t *bufRequest, mig_re
                        /* XXX - also gross */
                        if (likely(bufRequest->Head.msgh_id == MACH_NOTIFY_NO_SENDERS)) {
                                notify_server(&bufRequest->Head, &bufReply->Head);
                        /* XXX - also gross */
                        if (likely(bufRequest->Head.msgh_id == MACH_NOTIFY_NO_SENDERS)) {
                                notify_server(&bufRequest->Head, &bufReply->Head);
+                       } else if (the_demux == protocol_vproc_server) {
+                               
+#if !TARGET_OS_EMBEDDED
+                               /* Similarly gross. */
+                               if (xpc_domain_server(&bufRequest->Head, &bufReply->Head) == FALSE) {
+                                       (void)xpc_events_server(&bufRequest->Head, &bufReply->Head);
+                               }
+#else
+                               (void)xpc_events_server(&bufRequest->Head, &bufReply->Head);
+#endif
                        }
                }
 
                        }
                }
 
@@ -1215,8 +1176,8 @@ runtime_closelog(void)
        runtime_log_push();
 
        if (ourlogfile) {
        runtime_log_push();
 
        if (ourlogfile) {
-               launchd_assumes(fflush(ourlogfile) == 0);
-               launchd_assumes(runtime_fsync(fileno(ourlogfile)) != -1);
+               (void)launchd_assumes(fflush(ourlogfile) == 0);
+               (void)launchd_assumes(runtime_fsync(fileno(ourlogfile)) != -1);
        }
 }
 
        }
 }
 
@@ -1275,11 +1236,11 @@ runtime_vsyslog(struct runtime_syslog_attr *attr, const char *message, va_list a
                } else {
                        return;
                }
                } else {
                        return;
                }
-       } else if( attr->priority == LOG_SCOLDING ) {
+       } else if (attr->priority == LOG_SCOLDING) {
                attr->priority = g_log_strict_usage ? LOG_NOTICE : LOG_DEBUG;
        }
 
                attr->priority = g_log_strict_usage ? LOG_NOTICE : LOG_DEBUG;
        }
 
-       if( attr->priority & LOG_CONSOLE ) {
+       if (attr->priority & LOG_CONSOLE) {
                echo_to_console = true;
                attr->priority &= ~LOG_CONSOLE;
        }
                echo_to_console = true;
                attr->priority &= ~LOG_CONSOLE;
        }
@@ -1290,7 +1251,7 @@ runtime_vsyslog(struct runtime_syslog_attr *attr, const char *message, va_list a
 
        vsnprintf(newmsg, sizeof(newmsg), message, args);
 
 
        vsnprintf(newmsg, sizeof(newmsg), message, args);
 
-       if( g_console && (unlikely(low_level_debug) || echo_to_console) ) {
+       if (g_console && (unlikely(low_level_debug) || echo_to_console)) {
                fprintf(g_console, "%s %u\t%s %u\t%s\n", attr->from_name, attr->from_pid, attr->about_name, attr->about_pid, newmsg);
        }
 
                fprintf(g_console, "%s %u\t%s %u\t%s\n", attr->from_name, attr->from_pid, attr->about_name, attr->about_pid, newmsg);
        }
 
@@ -1363,7 +1324,7 @@ runtime_log_pack(vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
 
        offset = (void *)*outval;
 
 
        offset = (void *)*outval;
 
-       if( g_log_per_user_shutdown && !ourlogfile && !pid1_magic && shutdown_in_progress ) {
+       if (g_log_per_user_shutdown && !ourlogfile && !pid1_magic && shutdown_in_progress) {
                char logfile[NAME_MAX];
                snprintf(logfile, sizeof(logfile), "/var/tmp/launchd-%s.shutdown.log", g_username);
                
                char logfile[NAME_MAX];
                snprintf(logfile, sizeof(logfile), "/var/tmp/launchd-%s.shutdown.log", g_username);
                
@@ -1375,15 +1336,16 @@ runtime_log_pack(vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
        }
 
        static int64_t shutdown_start = 0;
        }
 
        static int64_t shutdown_start = 0;
-       if( shutdown_start == 0 ) {
+       if (shutdown_start == 0) {
                shutdown_start = runtime_get_wall_time();
        }
 
        while ((lm = STAILQ_FIRST(&logmsg_queue))) {
                int64_t log_delta = lm->when - shutdown_start;
                shutdown_start = runtime_get_wall_time();
        }
 
        while ((lm = STAILQ_FIRST(&logmsg_queue))) {
                int64_t log_delta = lm->when - shutdown_start;
-               if( !pid1_magic && ourlogfile ) {
+               if (!pid1_magic && ourlogfile) {
                        fprintf(ourlogfile, "%8lld%6u %-40s%6u %-40s %s\n", log_delta,
                                        lm->from_pid, lm->from_name, lm->about_pid, lm->about_name, lm->msg);
                        fprintf(ourlogfile, "%8lld%6u %-40s%6u %-40s %s\n", log_delta,
                                        lm->from_pid, lm->from_name, lm->about_pid, lm->about_name, lm->msg);
+                       fflush(ourlogfile);
                }
 
                lm->from_name_offset = lm->from_name - (char *)lm;
                }
 
                lm->from_name_offset = lm->from_name - (char *)lm;
@@ -1398,7 +1360,7 @@ runtime_log_pack(vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
                logmsg_remove(lm);
        }
        
                logmsg_remove(lm);
        }
        
-       if( ourlogfile ) {
+       if (ourlogfile) {
                fflush(ourlogfile);
        }
 
                fflush(ourlogfile);
        }
 
@@ -1428,8 +1390,8 @@ runtime_log_uncork_pending_drain(void)
        drain_reply_port = MACH_PORT_NULL;
 
        if (unlikely(errno = job_mig_log_drain_reply(tmp_port, 0, outval, outvalCnt))) {
        drain_reply_port = MACH_PORT_NULL;
 
        if (unlikely(errno = job_mig_log_drain_reply(tmp_port, 0, outval, outvalCnt))) {
-               launchd_assumes(errno == MACH_SEND_INVALID_DEST);
-               launchd_assumes(launchd_mport_deallocate(tmp_port) == KERN_SUCCESS);
+               (void)launchd_assumes(errno == MACH_SEND_INVALID_DEST);
+               (void)launchd_assumes(launchd_mport_deallocate(tmp_port) == KERN_SUCCESS);
        }
 
        mig_deallocate(outval, outvalCnt);
        }
 
        mig_deallocate(outval, outvalCnt);
@@ -1445,11 +1407,11 @@ runtime_log_push(void)
        vm_offset_t outval;
 
        if (logmsg_queue_cnt == 0) {
        vm_offset_t outval;
 
        if (logmsg_queue_cnt == 0) {
-               launchd_assumes(STAILQ_EMPTY(&logmsg_queue));
+               (void)launchd_assumes(STAILQ_EMPTY(&logmsg_queue));
                return;
        } else if (!pid1_magic) {
                if (runtime_log_pack(&outval, &outvalCnt) == 0) {
                return;
        } else if (!pid1_magic) {
                if (runtime_log_pack(&outval, &outvalCnt) == 0) {
-                       launchd_assumes(_vprocmgr_log_forward(inherited_bootstrap_port, (void *)outval, outvalCnt) == NULL);
+                       (void)launchd_assumes(_vprocmgr_log_forward(inherited_bootstrap_port, (void *)outval, outvalCnt) == NULL);
                        mig_deallocate(outval, outvalCnt);
                }
                return;
                        mig_deallocate(outval, outvalCnt);
                }
                return;
@@ -1467,7 +1429,7 @@ runtime_log_push(void)
 
        pthread_mutex_lock(&ourlock);
 
 
        pthread_mutex_lock(&ourlock);
 
-       if( unlikely(ourlogfile == NULL) && g_log_pid1_shutdown ) {
+       if (unlikely(ourlogfile == NULL) && g_log_pid1_shutdown) {
                rename("/var/log/launchd-shutdown.log", "/var/log/launchd-shutdown.log.1");
                ourlogfile = fopen("/var/log/launchd-shutdown.log", "a");
        }
                rename("/var/log/launchd-shutdown.log", "/var/log/launchd-shutdown.log.1");
                ourlogfile = fopen("/var/log/launchd-shutdown.log", "a");
        }
@@ -1511,7 +1473,7 @@ runtime_log_forward(uid_t forward_uid, gid_t forward_gid, vm_offset_t inval, mac
                 * can't safely increment our counter because something obviously got screwed
                 * up along the way, since this should always be at least sizeof(struct logmsg_s).
                 */
                 * can't safely increment our counter because something obviously got screwed
                 * up along the way, since this should always be at least sizeof(struct logmsg_s).
                 */
-               if( !launchd_assumes(lm_walk->obj_sz > 0) ) {
+               if (!launchd_assumes(lm_walk->obj_sz > 0)) {
                        runtime_syslog(LOG_WARNING, "Encountered a log message of size 0 with %u bytes left in forwarded data. Ignoring remaining messages.", data_left);
                        break;
                }
                        runtime_syslog(LOG_WARNING, "Encountered a log message of size 0 with %u bytes left in forwarded data. Ignoring remaining messages.", data_left);
                        break;
                }
@@ -1549,11 +1511,11 @@ runtime_log_forward(uid_t forward_uid, gid_t forward_gid, vm_offset_t inval, mac
 kern_return_t
 runtime_log_drain(mach_port_t srp, vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
 {
 kern_return_t
 runtime_log_drain(mach_port_t srp, vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
 {
-       launchd_assumes(drain_reply_port == 0);
+       (void)launchd_assumes(drain_reply_port == 0);
 
        if ((logmsg_queue_cnt == 0) || shutdown_in_progress || fake_shutdown_in_progress) {
                drain_reply_port = srp;
 
        if ((logmsg_queue_cnt == 0) || shutdown_in_progress || fake_shutdown_in_progress) {
                drain_reply_port = srp;
-               launchd_assumes(launchd_mport_notify_req(drain_reply_port, MACH_NOTIFY_DEAD_NAME) == KERN_SUCCESS);
+               (void)launchd_assumes(launchd_mport_notify_req(drain_reply_port, MACH_NOTIFY_DEAD_NAME) == KERN_SUCCESS);
 
                return MIG_NO_REPLY;
        }
 
                return MIG_NO_REPLY;
        }
@@ -1588,7 +1550,7 @@ runtime_del_ref(void)
 {
        if (!pid1_magic) {
        #if !TARGET_OS_EMBEDDED
 {
        if (!pid1_magic) {
        #if !TARGET_OS_EMBEDDED
-               if( _vproc_transaction_count() == 0 ) {
+               if (_vproc_transaction_count() == 0) {
                        runtime_syslog(LOG_INFO, "Exiting cleanly.");
                }
                
                        runtime_syslog(LOG_INFO, "Exiting cleanly.");
                }
                
@@ -1626,16 +1588,16 @@ runtime_del_weak_ref(void)
 void
 runtime_install_timer(void)
 {
 void
 runtime_install_timer(void)
 {
-       if( !pid1_magic && runtime_busy_cnt == 0 ) {
-               launchd_assumes(kevent_mod((uintptr_t)&g_runtime_busy_time, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, 30, root_jobmgr) != -1);
+       if (!pid1_magic && runtime_busy_cnt == 0) {
+               (void)launchd_assumes(kevent_mod((uintptr_t)&g_runtime_busy_time, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, 30, root_jobmgr) != -1);
        }
 }
 
 void
 runtime_remove_timer(void)
 {
        }
 }
 
 void
 runtime_remove_timer(void)
 {
-       if( !pid1_magic && runtime_busy_cnt > 0 ) {
-               launchd_assumes(kevent_mod((uintptr_t)&g_runtime_busy_time, EVFILT_TIMER, EV_DELETE, 0, 0, NULL) != -1);
+       if (!pid1_magic && runtime_busy_cnt > 0) {
+               (void)launchd_assumes(kevent_mod((uintptr_t)&g_runtime_busy_time, EVFILT_TIMER, EV_DELETE, 0, 0, NULL) != -1);
        }
 }
 
        }
 }
 
@@ -1645,13 +1607,13 @@ catch_mach_exception_raise(mach_port_t exception_port __attribute__((unused)), m
 {
        pid_t p4t = -1;
 
 {
        pid_t p4t = -1;
 
-       launchd_assumes(pid_for_task(task, &p4t) == 0);
+       (void)launchd_assumes(pid_for_task(task, &p4t) == 0);
        
        runtime_syslog(LOG_NOTICE, "%s(): PID: %u thread: 0x%x type: 0x%x code: %p codeCnt: 0x%x",
                        __func__, p4t, thread, exception, code, codeCnt);
        
        
        runtime_syslog(LOG_NOTICE, "%s(): PID: %u thread: 0x%x type: 0x%x code: %p codeCnt: 0x%x",
                        __func__, p4t, thread, exception, code, codeCnt);
        
-       launchd_assumes(launchd_mport_deallocate(thread) == KERN_SUCCESS);
-       launchd_assumes(launchd_mport_deallocate(task) == KERN_SUCCESS);
+       (void)launchd_assumes(launchd_mport_deallocate(thread) == KERN_SUCCESS);
+       (void)launchd_assumes(launchd_mport_deallocate(task) == KERN_SUCCESS);
 
        return KERN_SUCCESS;
 }
 
        return KERN_SUCCESS;
 }
@@ -1679,7 +1641,7 @@ catch_mach_exception_raise_state_identity(mach_port_t exception_port __attribute
 {
        pid_t p4t = -1;
 
 {
        pid_t p4t = -1;
 
-       launchd_assumes(pid_for_task(task, &p4t) == 0);
+       (void)launchd_assumes(pid_for_task(task, &p4t) == 0);
 
        runtime_syslog(LOG_NOTICE, "%s(): PID: %u thread: 0x%x type: 0x%x code: %p codeCnt: 0x%x flavor: %p old_state: %p old_stateCnt: 0x%x new_state: %p new_stateCnt: %p",
                        __func__, p4t, thread, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
 
        runtime_syslog(LOG_NOTICE, "%s(): PID: %u thread: 0x%x type: 0x%x code: %p codeCnt: 0x%x flavor: %p old_state: %p old_stateCnt: 0x%x new_state: %p new_stateCnt: %p",
                        __func__, p4t, thread, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
@@ -1687,8 +1649,8 @@ catch_mach_exception_raise_state_identity(mach_port_t exception_port __attribute
        memcpy(new_state, old_state, old_stateCnt * sizeof(old_state[0]));
        *new_stateCnt = old_stateCnt;
 
        memcpy(new_state, old_state, old_stateCnt * sizeof(old_state[0]));
        *new_stateCnt = old_stateCnt;
 
-       launchd_assumes(launchd_mport_deallocate(thread) == KERN_SUCCESS);
-       launchd_assumes(launchd_mport_deallocate(task) == KERN_SUCCESS);
+       (void)launchd_assumes(launchd_mport_deallocate(thread) == KERN_SUCCESS);
+       (void)launchd_assumes(launchd_mport_deallocate(task) == KERN_SUCCESS);
 
        return KERN_SUCCESS;
 }
 
        return KERN_SUCCESS;
 }
@@ -1708,7 +1670,7 @@ launchd_log_vm_stats(void)
                return;
        }
 
                return;
        }
 
-       launchd_assumes(count == HOST_VM_INFO_COUNT);
+       (void)launchd_assumes(count == HOST_VM_INFO_COUNT);
 
        if (did_first_pass) {
                runtime_syslog(LOG_DEBUG, "VM statistics (now - orig): Free: %d Active: %d Inactive: %d Reactivations: %d PageIns: %d PageOuts: %d Faults: %d COW-Faults: %d Purgeable: %d Purges: %d",
 
        if (did_first_pass) {
                runtime_syslog(LOG_DEBUG, "VM statistics (now - orig): Free: %d Active: %d Inactive: %d Reactivations: %d PageIns: %d PageOuts: %d Faults: %d COW-Faults: %d Purgeable: %d Purges: %d",
@@ -1747,7 +1709,7 @@ runtime_get_wall_time(void)
        struct timeval tv;
        int64_t r;
 
        struct timeval tv;
        int64_t r;
 
-       launchd_assumes(gettimeofday(&tv, NULL) != -1);
+       (void)launchd_assumes(gettimeofday(&tv, NULL) != -1);
 
        r = tv.tv_sec;
        r *= USEC_PER_SEC;
 
        r = tv.tv_sec;
        r *= USEC_PER_SEC;
@@ -1827,42 +1789,40 @@ do_file_init(void)
                low_level_debug = true;
        }
        
                low_level_debug = true;
        }
        
-       if( stat("/var/db/.launchd_disable_sudden_termination", &sb) == 0 ) {
-               g_force_old_kill_path = true;
-       }
-       
-       if( stat("/var/db/.launchd_log_per_user_shutdown", &sb) == 0 ) {
+       if (stat("/var/db/.launchd_log_per_user_shutdown", &sb) == 0) {
                g_log_per_user_shutdown = true;
        }
        
                g_log_per_user_shutdown = true;
        }
        
-       if( !pid1_magic && stat("/var/db/.launchd_no_flat_per_user_namespace", &sb) == 0 ) {
-               g_flat_mach_namespace = false;
-       }
-       
-       if( pid1_magic && stat("/var/db/.launchd_simulate_pid1_crash", &sb) == 0 ) {
-               g_simulate_pid1_crash = true;
-       }
-       
-       if( pid1_magic && stat("/var/db/.launchd_use_gmalloc", &sb) == 0 ) {
+       if (stat("/var/db/.launchd_use_gmalloc", &sb) == 0) {
                g_use_gmalloc = true;
        }
                g_use_gmalloc = true;
        }
+
+       if (stat("/var/db/.launchd_malloc_log_stacks", &sb) == 0) {
+               g_malloc_log_stacks = true;
+               g_use_gmalloc = false;
+       }
        
        
-       if( pid1_magic && stat("/var/db/.launchd_log_pid1_shutdown", &sb) == 0 ) {
+       if (pid1_magic && stat("/var/db/.launchd_log_pid1_shutdown", &sb) == 0) {
                g_log_pid1_shutdown = true;
        }
        
        char bootargs[128];
        size_t len = sizeof(bootargs) - 1;
        int r = pid1_magic ? sysctlbyname("kern.bootargs", bootargs, &len, NULL, 0) : -1;
                g_log_pid1_shutdown = true;
        }
        
        char bootargs[128];
        size_t len = sizeof(bootargs) - 1;
        int r = pid1_magic ? sysctlbyname("kern.bootargs", bootargs, &len, NULL, 0) : -1;
-       if( r == 0 && strnstr(bootargs, "-v", len) != NULL ) {
-               g_verbose_boot = true;
+       if (r == 0) {
+               if (strnstr(bootargs, "-v", len)) {
+                       g_verbose_boot = true;
+               }
+               if (strnstr(bootargs, "launchd_trap_sigkill_bugs", len)) {
+                       g_trap_sigkill_bugs = true;
+               }
        }
        
        }
        
-       if( pid1_magic && g_verbose_boot && stat("/var/db/.launchd_shutdown_debugging", &sb) == 0 ) {
+       if (pid1_magic && g_verbose_boot && stat("/var/db/.launchd_shutdown_debugging", &sb) == 0) {
                g_shutdown_debugging = true;
        }
        
                g_shutdown_debugging = true;
        }
        
-       if( stat("/var/db/.launchd_log_strict_usage", &sb) == 0 ) {
+       if (stat("/var/db/.launchd_log_strict_usage", &sb) == 0) {
                g_log_strict_usage = true;
        }
 }
                g_log_strict_usage = true;
        }
 }
index 416efde19b392e0c160bcac5211d7852a2854669..dc52474cf5a010a2bb7b25726d094c4cf3bec700 100644 (file)
 #define        unlikely(x)     __builtin_expect((bool)(x), false)
 
 struct ldcred {
 #define        unlikely(x)     __builtin_expect((bool)(x), false)
 
 struct ldcred {
-       uid_t   euid;
-       uid_t   uid;
-       gid_t   egid;
-       gid_t   gid;
-       pid_t   pid;
+       uid_t           euid;
+       uid_t           uid;
+       gid_t           egid;
+       gid_t           gid;
+       pid_t           pid;
+       au_asid_t       asid;
+       mach_port_t     asport;
 };
 
 /*
 };
 
 /*
@@ -105,10 +107,12 @@ extern char g_my_label[128];
 extern bool g_shutdown_debugging;
 extern bool g_verbose_boot;
 extern bool g_use_gmalloc;
 extern bool g_shutdown_debugging;
 extern bool g_verbose_boot;
 extern bool g_use_gmalloc;
+extern bool g_malloc_log_stacks;
 extern bool g_log_per_user_shutdown;
 extern bool g_log_strict_usage;
 extern bool g_embedded_shutdown_log;
 extern bool g_runtime_busy_time;
 extern bool g_log_per_user_shutdown;
 extern bool g_log_strict_usage;
 extern bool g_embedded_shutdown_log;
 extern bool g_runtime_busy_time;
+extern bool g_trap_sigkill_bugs;
 extern size_t runtime_busy_cnt;
 extern int32_t g_sync_frequency;
 extern pid_t g_wsp;
 extern size_t runtime_busy_cnt;
 extern int32_t g_sync_frequency;
 extern pid_t g_wsp;
@@ -141,7 +145,6 @@ struct ldcred *runtime_get_caller_creds(void);
 
 const char *signal_to_C_name(unsigned int sig);
 const char *reboot_flags_to_C_names(unsigned int flags);
 
 const char *signal_to_C_name(unsigned int sig);
 const char *reboot_flags_to_C_names(unsigned int flags);
-const char *proc_flags_to_C_names(unsigned int flags);
 
 int kevent_bulk_mod(struct kevent *kev, size_t kev_cnt);
 int kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata);
 
 int kevent_bulk_mod(struct kevent *kev, size_t kev_cnt);
 int kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata);
@@ -188,6 +191,7 @@ kern_return_t launchd_mport_create_recv(mach_port_t *name);
 kern_return_t launchd_mport_deallocate(mach_port_t name);
 kern_return_t launchd_mport_make_send(mach_port_t name);
 kern_return_t launchd_mport_copy_send(mach_port_t name);
 kern_return_t launchd_mport_deallocate(mach_port_t name);
 kern_return_t launchd_mport_make_send(mach_port_t name);
 kern_return_t launchd_mport_copy_send(mach_port_t name);
+kern_return_t launchd_mport_make_send_once(mach_port_t name, mach_port_t *so);
 kern_return_t launchd_mport_close_recv(mach_port_t name);
 
 #endif
 kern_return_t launchd_mport_close_recv(mach_port_t name);
 
 #endif
index 957b43fad0ae7cf7841445234f5e160480683d3f..0dcd9f93236e6fe1d5223466f34712762ed9fc07 100644 (file)
@@ -18,7 +18,7 @@
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
-static const char *const __rcs_file_version__ = "$Revision: 23921 $";
+static const char *const __rcs_file_version__ = "$Revision: 24557 $";
 
 #include "config.h"
 #include "launchd_unix_ipc.h"
 
 #include "config.h"
 #include "launchd_unix_ipc.h"
@@ -174,7 +174,7 @@ ipc_server_init(void)
 
 out_bad:
        if (!ipc_inited && fd != -1) {
 
 out_bad:
        if (!ipc_inited && fd != -1) {
-               launchd_assumes(runtime_close(fd) == 0);
+               (void)launchd_assumes(runtime_close(fd) == 0);
        }
 }
 
        }
 }
 
@@ -186,7 +186,7 @@ ipc_open(int fd, job_t j)
        fcntl(fd, F_SETFL, O_NONBLOCK);
 
        c->kqconn_callback = ipc_callback;
        fcntl(fd, F_SETFL, O_NONBLOCK);
 
        c->kqconn_callback = ipc_callback;
-       if( j ) {
+       if (j) {
                c->conn = launchd_fdopen(-1, fd);
        } else {
                c->conn = launchd_fdopen(fd, -1);
                c->conn = launchd_fdopen(-1, fd);
        } else {
                c->conn = launchd_fdopen(fd, -1);
@@ -244,7 +244,7 @@ static void
 set_user_env(launch_data_t obj, const char *key, void *context __attribute__((unused)))
 {
        const char *v = launch_data_get_string(obj);
 set_user_env(launch_data_t obj, const char *key, void *context __attribute__((unused)))
 {
        const char *v = launch_data_get_string(obj);
-       if( v ) {
+       if (v) {
                setenv(key, v, 1);
        } else {
                runtime_syslog(LOG_WARNING, "Attempt to set NULL environment variable: %s (type = %d)", key, launch_data_get_type(obj));
                setenv(key, v, 1);
        } else {
                runtime_syslog(LOG_WARNING, "Attempt to set NULL environment variable: %s (type = %d)", key, launch_data_get_type(obj));
@@ -278,7 +278,7 @@ ipc_close_fds(launch_data_t o)
                break;
        case LAUNCH_DATA_FD:
                if (launch_data_get_fd(o) != -1) {
                break;
        case LAUNCH_DATA_FD:
                if (launch_data_get_fd(o) != -1) {
-                       launchd_assumes(runtime_close(launch_data_get_fd(o)) == 0);
+                       (void)launchd_assumes(runtime_close(launch_data_get_fd(o)) == 0);
                }
                break;
        default:
                }
                break;
        default:
@@ -365,14 +365,14 @@ ipc_readmsg2(launch_data_t data, const char *cmd, void *context)
        bool allow_privileged_ops = !rmc->c->j;
 #endif
        
        bool allow_privileged_ops = !rmc->c->j;
 #endif
        
-       if( rmc->c->j && strcmp(cmd, LAUNCH_KEY_CHECKIN) == 0 ) {
+       if (rmc->c->j && strcmp(cmd, LAUNCH_KEY_CHECKIN) == 0) {
                resp = job_export(rmc->c->j);
                job_checkin(rmc->c->j);
                resp = job_export(rmc->c->j);
                job_checkin(rmc->c->j);
-       } else if( allow_privileged_ops ) {
+       } else if (allow_privileged_ops) {
        #if TARGET_OS_EMBEDDED
                g_embedded_privileged_action = rmc->c->j && job_is_god(rmc->c->j);
        #endif
        #if TARGET_OS_EMBEDDED
                g_embedded_privileged_action = rmc->c->j && job_is_god(rmc->c->j);
        #endif
-               if( data == NULL ) {
+               if (data == NULL) {
                        if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) {
                                launchd_shutdown();
                                resp = launch_data_new_errno(0);
                        if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) {
                                launchd_shutdown();
                                resp = launch_data_new_errno(0);
@@ -395,18 +395,18 @@ ipc_readmsg2(launch_data_t data, const char *cmd, void *context)
                        }
                } else {
                        if (!strcmp(cmd, LAUNCH_KEY_STARTJOB)) {
                        }
                } else {
                        if (!strcmp(cmd, LAUNCH_KEY_STARTJOB)) {
-                               if ((j = job_find(launch_data_get_string(data))) != NULL) {
+                               if ((j = job_find(NULL, launch_data_get_string(data))) != NULL) {
                                        errno = job_dispatch(j, true) ? 0 : errno;
                                }
                                resp = launch_data_new_errno(errno);
                        } else if (!strcmp(cmd, LAUNCH_KEY_STOPJOB)) {
                                        errno = job_dispatch(j, true) ? 0 : errno;
                                }
                                resp = launch_data_new_errno(errno);
                        } else if (!strcmp(cmd, LAUNCH_KEY_STOPJOB)) {
-                               if ((j = job_find(launch_data_get_string(data))) != NULL) {
+                               if ((j = job_find(NULL, launch_data_get_string(data))) != NULL) {
                                        errno = 0;
                                        job_stop(j);
                                }
                                resp = launch_data_new_errno(errno);
                        } else if (!strcmp(cmd, LAUNCH_KEY_REMOVEJOB)) {
                                        errno = 0;
                                        job_stop(j);
                                }
                                resp = launch_data_new_errno(errno);
                        } else if (!strcmp(cmd, LAUNCH_KEY_REMOVEJOB)) {
-                               if ((j = job_find(launch_data_get_string(data))) != NULL) {
+                               if ((j = job_find(NULL, launch_data_get_string(data))) != NULL) {
                                        errno = 0;
                                        job_remove(j);
                                }
                                        errno = 0;
                                        job_remove(j);
                                }
@@ -429,13 +429,13 @@ ipc_readmsg2(launch_data_t data, const char *cmd, void *context)
                        } else if (!strcmp(cmd, LAUNCH_KEY_SETRESOURCELIMITS)) {
                                resp = adjust_rlimits(data);
                        } else if (!strcmp(cmd, LAUNCH_KEY_GETJOB)) {
                        } else if (!strcmp(cmd, LAUNCH_KEY_SETRESOURCELIMITS)) {
                                resp = adjust_rlimits(data);
                        } else if (!strcmp(cmd, LAUNCH_KEY_GETJOB)) {
-                               if ((j = job_find(launch_data_get_string(data))) == NULL) {
+                               if ((j = job_find(NULL, launch_data_get_string(data))) == NULL) {
                                        resp = launch_data_new_errno(errno);
                                } else {
                                        resp = job_export(j);
                                        ipc_revoke_fds(resp);
                                }
                                        resp = launch_data_new_errno(errno);
                                } else {
                                        resp = job_export(j);
                                        ipc_revoke_fds(resp);
                                }
-                       } else if( !strcmp(cmd, LAUNCH_KEY_SETPRIORITYLIST) ) {
+                       } else if (!strcmp(cmd, LAUNCH_KEY_SETPRIORITYLIST)) {
                                resp = launch_data_new_errno(launchd_set_jetsam_priorities(data));
                        }
                }
                                resp = launch_data_new_errno(launchd_set_jetsam_priorities(data));
                        }
                }
@@ -471,7 +471,7 @@ adjust_rlimits(launch_data_t in)
        size_t i,ltmpsz;
 
        for (i = 0; i < RLIM_NLIMITS; i++) {
        size_t i,ltmpsz;
 
        for (i = 0; i < RLIM_NLIMITS; i++) {
-               launchd_assumes(getrlimit(i, l + i) != -1);
+               (void)launchd_assumes(getrlimit(i, l + i) != -1);
        }
 
        if (in) {
        }
 
        if (in) {
@@ -507,19 +507,19 @@ adjust_rlimits(launch_data_t in)
                                }
 
                                if (gval > 0) {
                                }
 
                                if (gval > 0) {
-                                       launchd_assumes(sysctl(gmib, 2, NULL, NULL, &gval, sizeof(gval)) != -1);
+                                       (void)launchd_assumes(sysctl(gmib, 2, NULL, NULL, &gval, sizeof(gval)) != -1);
                                } else {
                                        runtime_syslog(LOG_WARNING, "sysctl(\"%s\"): can't be zero", gstr);
                                }
                                if (pval > 0) {
                                } else {
                                        runtime_syslog(LOG_WARNING, "sysctl(\"%s\"): can't be zero", gstr);
                                }
                                if (pval > 0) {
-                                       launchd_assumes(sysctl(pmib, 2, NULL, NULL, &pval, sizeof(pval)) != -1);
+                                       (void)launchd_assumes(sysctl(pmib, 2, NULL, NULL, &pval, sizeof(pval)) != -1);
                                } else {
                                        runtime_syslog(LOG_WARNING, "sysctl(\"%s\"): can't be zero", pstr);
                                }
                        }
                                } else {
                                        runtime_syslog(LOG_WARNING, "sysctl(\"%s\"): can't be zero", pstr);
                                }
                        }
-                       launchd_assumes(setrlimit(i, ltmp + i) != -1);
+                       (void)launchd_assumes(setrlimit(i, ltmp + i) != -1);
                        /* the kernel may have clamped the values we gave it */
                        /* the kernel may have clamped the values we gave it */
-                       launchd_assumes(getrlimit(i, l + i) != -1);
+                       (void)launchd_assumes(getrlimit(i, l + i) != -1);
                }
        }
 
                }
        }
 
index b463966fbff6c204ac8dbdd40cab16fb63e4cd66..2193a33538cbd34a743c17d3be5276b407089a15 100644 (file)
@@ -25,6 +25,7 @@
 #include "launchd_runtime.h"
 #include "launchd_core_logic.h"
 #include "launch_priv.h"
 #include "launchd_runtime.h"
 #include "launchd_core_logic.h"
 #include "launch_priv.h"
+#include "launch_internal.h"
 
 struct conncb {
        kq_callback kqconn_callback;
 
 struct conncb {
        kq_callback kqconn_callback;
index 3a909359607182c8f7dca676f337b54b186724af..693bc1bfae68298f4d1332ae50a6d80362e31332 100644 (file)
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 #include "config.h"
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 #include "config.h"
-#if HAVE_SECURITY
-#include <Security/Authorization.h>
-#include <Security/AuthorizationTags.h>
-#include <Security/AuthSession.h>
-#endif
 #include <sys/types.h>
 #include <sys/select.h>
 #include <sys/event.h>
 #include <sys/types.h>
 #include <sys/select.h>
 #include <sys/event.h>
 #include <signal.h>
 #include <netdb.h>
 
 #include <signal.h>
 #include <netdb.h>
 
-#include "launch.h"
-
-#if __GNUC__ >= 4 && HAVE_SECURITY
-OSStatus SessionCreate(SessionCreationFlags flags, SessionAttributeBits attributes) __attribute__((weak));
+#if !TARGET_OS_EMBEDDED
+#include <bsm/audit.h>
+#include <bsm/audit_session.h>
 #endif
 
 #endif
 
+#include "launch.h"
+
 static int kq = 0;
 
 static void find_fds(launch_data_t o, const char *key __attribute__((unused)), void *context __attribute__((unused)))
 static int kq = 0;
 
 static void find_fds(launch_data_t o, const char *key __attribute__((unused)), void *context __attribute__((unused)))
@@ -181,7 +177,7 @@ int main(int argc __attribute__((unused)), char *argv[])
                        switch (fork()) {
                        case -1:
                                syslog(LOG_WARNING, "fork(): %m");
                        switch (fork()) {
                        case -1:
                                syslog(LOG_WARNING, "fork(): %m");
-                               if( errno != ENOMEM ) {
+                               if (errno != ENOMEM) {
                                        continue;
                                }
                                goto out;
                                        continue;
                                }
                                goto out;
@@ -194,14 +190,20 @@ int main(int argc __attribute__((unused)), char *argv[])
 
                        setpgid(0, 0);
 
 
                        setpgid(0, 0);
 
-#if HAVE_SECURITY
+#if !TARGET_OS_EMBEDDED
                        if ((tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SESSIONCREATE)) && launch_data_get_bool(tmp)) {
                        if ((tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SESSIONCREATE)) && launch_data_get_bool(tmp)) {
-                               if (SessionCreate) {
-                                       OSStatus scr = SessionCreate(0, 0);
-                                       if (scr != noErr)
-                                               syslog(LOG_NOTICE, "%s: SessionCreate() failed: %d", prog, scr);
+                               auditinfo_addr_t auinfo = {
+                                       .ai_termid = { .at_type = AU_IPv4 },
+                                       .ai_asid = AU_ASSIGN_ASID,
+                                       .ai_auid = getuid(),
+                                       .ai_flags = 0,
+                               };
+                               if (setaudit_addr(&auinfo, sizeof(auinfo)) == 0) {
+                                       char session[16]; 
+                                       snprintf(session, sizeof(session), "%x", auinfo.ai_asid);
+                                       setenv("SECURITYSESSIONID", session, 1);
                                } else {
                                } else {
-                                       syslog(LOG_NOTICE, "%s: SessionCreate == NULL!", prog);
+                                       syslog(LOG_NOTICE, "%s: Setting Audit Session ID failed: %d", prog, errno);
                                }
                        }
 #endif
                                }
                        }
 #endif
index be0209c6a4ed95efed713dac865ffa0c1b1626b5..ceed582653f11db4eee664dc11e7594f2816bad5 100644 (file)
 #include <sys/syslog.h>
 #include <sys/stat.h>
 #include <pthread.h>
 #include <sys/syslog.h>
 #include <sys/stat.h>
 #include <pthread.h>
+#include <stdlib.h>
 
 #include "protocol_vproc.h"
 
 
 #include "protocol_vproc.h"
 
+mach_port_t    bootstrap_port = MACH_PORT_NULL;
+
+void
+bootstrap_init(void)
+{
+       kern_return_t kr = task_get_special_port(task_self_trap(), TASK_BOOTSTRAP_PORT, &bootstrap_port);
+       if (kr != KERN_SUCCESS) {
+               abort();
+       }
+}
+
 kern_return_t
 bootstrap_create_server(mach_port_t bp, cmd_t server_cmd, uid_t server_uid, boolean_t on_demand, mach_port_t *server_port)
 {
 kern_return_t
 bootstrap_create_server(mach_port_t bp, cmd_t server_cmd, uid_t server_uid, boolean_t on_demand, mach_port_t *server_port)
 {
@@ -124,13 +136,15 @@ bootstrap_create_service(mach_port_t bp, name_t service_name, mach_port_t *sp)
 kern_return_t
 bootstrap_check_in(mach_port_t bp, const name_t service_name, mach_port_t *sp)
 {
 kern_return_t
 bootstrap_check_in(mach_port_t bp, const name_t service_name, mach_port_t *sp)
 {
-       return vproc_mig_check_in2(bp, (char *)service_name, sp, 0);
+       uuid_t junk;
+       return vproc_mig_check_in2(bp, (char *)service_name, sp, junk, 0);
 }
 
 kern_return_t
 bootstrap_check_in2(mach_port_t bp, const name_t service_name, mach_port_t *sp, uint64_t flags)
 {
 }
 
 kern_return_t
 bootstrap_check_in2(mach_port_t bp, const name_t service_name, mach_port_t *sp, uint64_t flags)
 {
-       return vproc_mig_check_in2(bp, (char *)service_name, sp, flags);
+       uuid_t junk;
+       return vproc_mig_check_in2(bp, (char *)service_name, sp, junk, flags);
 }
 
 kern_return_t
 }
 
 kern_return_t
@@ -146,10 +160,11 @@ bootstrap_look_up_per_user(mach_port_t bp, const name_t service_name, uid_t targ
                return kr;
        }
 
                return kr;
        }
 
-       if( !service_name ) {
+       if (!service_name) {
                *sp = puc;
        } else {
                *sp = puc;
        } else {
-               kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, 0, 0);
+               uuid_t junk;
+               kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, 0, junk, 0);
                mach_port_deallocate(mach_task_self(), puc);
        }
 
                mach_port_deallocate(mach_task_self(), puc);
        }
 
@@ -172,35 +187,21 @@ bootstrap_look_up(mach_port_t bp, const name_t service_name, mach_port_t *sp)
 kern_return_t
 bootstrap_look_up2(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, uint64_t flags)
 {
 kern_return_t
 bootstrap_look_up2(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, uint64_t flags)
 {
-       static pthread_mutex_t bslu2_lock = PTHREAD_MUTEX_INITIALIZER;
-       static mach_port_t prev_bp;
-       static mach_port_t prev_sp;
-       static name_t prev_name;
+       uuid_t instance_id;
+       return bootstrap_look_up3(bp, service_name, sp, target_pid, instance_id, flags);
+}
+
+kern_return_t
+bootstrap_look_up3(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, const uuid_t instance_id, uint64_t flags)
+{
        audit_token_t au_tok;
        audit_token_t au_tok;
-       bool per_pid_lookup = flags & BOOTSTRAP_PER_PID_SERVICE;
        bool privileged_server_lookup = flags & BOOTSTRAP_PRIVILEGED_SERVER;
        kern_return_t kr = 0;
        mach_port_t puc;
        bool privileged_server_lookup = flags & BOOTSTRAP_PRIVILEGED_SERVER;
        kern_return_t kr = 0;
        mach_port_t puc;
-       
-       pthread_mutex_lock(&bslu2_lock);
-       
-       if (per_pid_lookup || privileged_server_lookup) {
-               goto skip_cache;
-       }
-       
-       if (prev_sp) {
-               if ((bp == prev_bp) && (strncmp(prev_name, service_name, sizeof(name_t)) == 0)
-                       && (mach_port_mod_refs(mach_task_self(), prev_sp, MACH_PORT_RIGHT_SEND, 1) == 0)) {
-                       *sp = prev_sp;
-                       goto out;
-               } else {
-                       mach_port_deallocate(mach_task_self(), prev_sp);
-                       prev_sp = 0;
-               }
-       }
-       
-skip_cache:
-       if ((kr = vproc_mig_look_up2(bp, (char *)service_name, sp, &au_tok, target_pid, flags)) != VPROC_ERR_TRY_PER_USER) {
+
+       // We have to cast instance_id here because the MIG-generated method
+       // doesn't expect a const parameter.
+       if ((kr = vproc_mig_look_up2(bp, (char *)service_name, sp, &au_tok, target_pid, (unsigned char*)instance_id, flags)) != VPROC_ERR_TRY_PER_USER) {
                goto out;
        }
        
                goto out;
        }
        
@@ -208,17 +209,10 @@ skip_cache:
                goto out;
        }
        
                goto out;
        }
        
-       kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, target_pid, flags);
+       kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, target_pid, (unsigned char*)instance_id, flags);
        mach_port_deallocate(mach_task_self(), puc);
        mach_port_deallocate(mach_task_self(), puc);
-       
+
 out:
 out:
-       if (!(per_pid_lookup || privileged_server_lookup) && kr == 0 && prev_sp == 0 && mach_port_mod_refs(mach_task_self(), *sp, MACH_PORT_RIGHT_SEND, 1) == 0) {
-               /* We're going to hold on to a send right as a MRU cache */
-               prev_bp = bp;
-               prev_sp = *sp;
-               strlcpy(prev_name, service_name, sizeof(name_t));
-       }
-       
        if ((kr == 0) && privileged_server_lookup) {
                uid_t server_euid;
                
        if ((kr == 0) && privileged_server_lookup) {
                uid_t server_euid;
                
@@ -235,15 +229,26 @@ out:
                
                if (server_euid) {
                        mach_port_deallocate(mach_task_self(), *sp);
                
                if (server_euid) {
                        mach_port_deallocate(mach_task_self(), *sp);
+                       *sp = MACH_PORT_NULL;
                        kr = BOOTSTRAP_NOT_PRIVILEGED;
                }
        }
                        kr = BOOTSTRAP_NOT_PRIVILEGED;
                }
        }
-       /* If performance becomes a problem, we should restructure this. */
-       pthread_mutex_unlock(&bslu2_lock);
-       
+
        return kr;
 }
 
        return kr;
 }
 
+kern_return_t
+bootstrap_check_in3(mach_port_t bp, const name_t service_name, mach_port_t *sp, uuid_t instance_id, uint64_t flags)
+{
+       return vproc_mig_check_in2(bp, (char *)service_name, sp, instance_id, flags);
+}
+
+kern_return_t
+bootstrap_get_root(mach_port_t bp, mach_port_t *root)
+{
+       return vproc_mig_get_root_bootstrap(bp, root);
+}
+
 kern_return_t
 bootstrap_status(mach_port_t bp, name_t service_name, bootstrap_status_t *service_active)
 {
 kern_return_t
 bootstrap_status(mach_port_t bp, name_t service_name, bootstrap_status_t *service_active)
 {
index 674f91984183e5a5fa98f39db5365843e097f2b0..076f93a1d38a438f0f793ab413b05eb1cbc37a37 100644 (file)
@@ -42,6 +42,7 @@
 #include <assert.h>
 #include <uuid/uuid.h>
 #include <sys/syscall.h>
 #include <assert.h>
 #include <uuid/uuid.h>
 #include <sys/syscall.h>
+#include <dlfcn.h>
 
 #ifdef __LP64__
 /* workaround: 5723161 */
 
 #ifdef __LP64__
 /* workaround: 5723161 */
@@ -122,31 +123,6 @@ struct launch_msg_header {
 
 #define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull
 
 
 #define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull
 
-struct _launch_data {
-       uint64_t type;
-       union {
-               struct {
-                       union {
-                               launch_data_t *_array;
-                               char *string;
-                               void *opaque;
-                               int64_t __junk;
-                       };
-                       union {
-                               uint64_t _array_cnt;
-                               uint64_t string_len;
-                               uint64_t opaque_size;
-                       };
-               };
-               int64_t fd;
-               uint64_t  mp;
-               uint64_t err;
-               int64_t number;
-               uint64_t boolean; /* We'd use 'bool' but this struct needs to be used under Rosetta, and sizeof(bool) is different between PowerPC and Intel */
-               double float_num;
-       };
-};
-
 enum {
        LAUNCHD_USE_CHECKIN_FD,
        LAUNCHD_USE_OTHER_FD,
 enum {
        LAUNCHD_USE_CHECKIN_FD,
        LAUNCHD_USE_OTHER_FD,
@@ -223,8 +199,8 @@ launch_client_init(void)
        if (where && where[0] != '\0') {
                strncpy(sun.sun_path, where, sizeof(sun.sun_path));
        } else {
        if (where && where[0] != '\0') {
                strncpy(sun.sun_path, where, sizeof(sun.sun_path));
        } else {
-               if( _vprocmgr_getsocket(spath) == 0 ) {
-                       if( (getenv("SUDO_COMMAND") || getenv("__USE_SYSTEM_LAUNCHD")) && geteuid() == 0 ) {
+               if (_vprocmgr_getsocket(spath) == 0) {
+                       if ((getenv("SUDO_COMMAND") || getenv("__USE_SYSTEM_LAUNCHD")) && geteuid() == 0) {
                                /* Talk to the system launchd. */
                                strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path));
                        } else {
                                /* Talk to the system launchd. */
                                strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path));
                        } else {
@@ -246,7 +222,7 @@ launch_client_init(void)
        (void)vproc_swap_integer(NULL, VPROC_GSK_EMBEDDEDROOTEQUIVALENT, NULL, &s_am_embedded_god);
 #endif
        if (-1 == connect(lfd, (struct sockaddr *)&sun, sizeof(sun))) {
        (void)vproc_swap_integer(NULL, VPROC_GSK_EMBEDDEDROOTEQUIVALENT, NULL, &s_am_embedded_god);
 #endif
        if (-1 == connect(lfd, (struct sockaddr *)&sun, sizeof(sun))) {
-               if( cifd != -1 || s_am_embedded_god ) {
+               if (cifd != -1 || s_am_embedded_god) {
                        /* There is NO security enforced by this check. This is just a hint to our
                         * library that we shouldn't error out due to failing to open this socket. If
                         * we inherited a trusted file descriptor, we shouldn't fail. This should be
                        /* There is NO security enforced by this check. This is just a hint to our
                         * library that we shouldn't error out due to failing to open this socket. If
                         * we inherited a trusted file descriptor, we shouldn't fail. This should be
@@ -273,7 +249,7 @@ out_bad:
                launchd_close(_lc->l, close);
        else if (lfd != -1)
                close(lfd);
                launchd_close(_lc->l, close);
        else if (lfd != -1)
                close(lfd);
-       if( cifd != -1 ) {
+       if (cifd != -1) {
                close(cifd);
        }
        if (_lc)
                close(cifd);
        }
        if (_lc)
@@ -284,7 +260,7 @@ out_bad:
 launch_data_t
 launch_data_alloc(launch_data_type_t t)
 {
 launch_data_t
 launch_data_alloc(launch_data_type_t t)
 {
-       launch_data_t d = calloc(1, sizeof(struct _launch));
+       launch_data_t d = calloc(1, sizeof(struct _launch_data));
 
        if (d) {
                d->type = t;
 
        if (d) {
                d->type = t;
@@ -293,6 +269,8 @@ launch_data_alloc(launch_data_type_t t)
                case LAUNCH_DATA_ARRAY:
                        d->_array = malloc(0);
                        break;
                case LAUNCH_DATA_ARRAY:
                        d->_array = malloc(0);
                        break;
+               case LAUNCH_DATA_OPAQUE:
+                       d->opaque = malloc(0);
                default:
                        break;
                }
                default:
                        break;
                }
@@ -315,8 +293,11 @@ launch_data_free(launch_data_t d)
        switch (d->type) {
        case LAUNCH_DATA_DICTIONARY:
        case LAUNCH_DATA_ARRAY:
        switch (d->type) {
        case LAUNCH_DATA_DICTIONARY:
        case LAUNCH_DATA_ARRAY:
-               for (i = 0; i < d->_array_cnt; i++)
-                       launch_data_free(d->_array[i]);
+               for (i = 0; i < d->_array_cnt; i++) {
+                       if (d->_array[i]) {
+                               launch_data_free(d->_array[i]);
+                       }
+               }
                free(d->_array);
                break;
        case LAUNCH_DATA_STRING:
                free(d->_array);
                break;
        case LAUNCH_DATA_STRING:
@@ -600,9 +581,9 @@ launchd_fdopen(int fd, int cifd)
        c->fd = fd;
        c->cifd = cifd;
 
        c->fd = fd;
        c->cifd = cifd;
 
-       if( c->fd == -1 || (c->fd != -1 && c->cifd != -1) ) {
+       if (c->fd == -1 || (c->fd != -1 && c->cifd != -1)) {
                c->which = LAUNCHD_USE_CHECKIN_FD;
                c->which = LAUNCHD_USE_CHECKIN_FD;
-       } else if( c->cifd == -1 ) {
+       } else if (c->cifd == -1) {
                c->which = LAUNCHD_USE_OTHER_FD;
        }
 
                c->which = LAUNCHD_USE_OTHER_FD;
        }
 
@@ -831,7 +812,7 @@ launchd_msg_send(launch_t lh, launch_data_t d)
        int r;
 
        int fd2use = launchd_getfd(lh);
        int r;
 
        int fd2use = launchd_getfd(lh);
-       if( fd2use == -1 ) {
+       if (fd2use == -1) {
                errno = EPERM;
                return -1;
        }
                errno = EPERM;
                return -1;
        }
@@ -849,8 +830,19 @@ launchd_msg_send(launch_t lh, launch_data_t d)
                /* hack, see the above assert to verify "correctness" */
                free(lh->sendbuf);
                lh->sendbuf = malloc(good_enough_size);
                /* hack, see the above assert to verify "correctness" */
                free(lh->sendbuf);
                lh->sendbuf = malloc(good_enough_size);
+               if (!lh->sendbuf) {
+                       errno = ENOMEM;
+                       return -1;
+               }
+
                free(lh->sendfds);
                lh->sendfds = malloc(4 * 1024);
                free(lh->sendfds);
                lh->sendfds = malloc(4 * 1024);
+               if (!lh->sendfds) {
+                       free(lh->sendbuf);
+                       lh->sendbuf = NULL;
+                       errno = ENOMEM;
+                       return -1;
+               }
 
                lh->sendlen = launch_data_pack(d, lh->sendbuf, good_enough_size, lh->sendfds, &fd_slots_used);
 
 
                lh->sendlen = launch_data_pack(d, lh->sendbuf, good_enough_size, lh->sendfds, &fd_slots_used);
 
@@ -993,7 +985,7 @@ static inline bool
 uuid_data_is_null(launch_data_t d)
 {
        bool result = false;
 uuid_data_is_null(launch_data_t d)
 {
        bool result = false;
-       if( launch_data_get_type(d) == LAUNCH_DATA_OPAQUE && launch_data_get_opaque_size(d) == sizeof(uuid_t) ) {
+       if (launch_data_get_type(d) == LAUNCH_DATA_OPAQUE && launch_data_get_opaque_size(d) == sizeof(uuid_t)) {
                uuid_t existing_uuid;
                memcpy(existing_uuid, launch_data_get_opaque(d), sizeof(uuid_t));
                
                uuid_t existing_uuid;
                memcpy(existing_uuid, launch_data_get_opaque(d), sizeof(uuid_t));
                
@@ -1022,7 +1014,7 @@ launch_msg_internal(launch_data_t d)
        }
 
        int fd2use = -1;
        }
 
        int fd2use = -1;
-       if( (launch_data_get_type(d) == LAUNCH_DATA_STRING && strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) == 0) || s_am_embedded_god ) {
+       if ((launch_data_get_type(d) == LAUNCH_DATA_STRING && strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) == 0) || s_am_embedded_god) {
                _lc->l->which = LAUNCHD_USE_CHECKIN_FD;
        } else {
                _lc->l->which = LAUNCHD_USE_OTHER_FD;
                _lc->l->which = LAUNCHD_USE_CHECKIN_FD;
        } else {
                _lc->l->which = LAUNCHD_USE_OTHER_FD;
@@ -1030,7 +1022,7 @@ launch_msg_internal(launch_data_t d)
        
        fd2use = launchd_getfd(_lc->l);
        
        
        fd2use = launchd_getfd(_lc->l);
        
-       if( fd2use == -1 ) {
+       if (fd2use == -1) {
                errno = EPERM;
                return NULL;
        }
                errno = EPERM;
                return NULL;
        }
@@ -1039,31 +1031,31 @@ launch_msg_internal(launch_data_t d)
        uuid_t uuid;
        launch_data_t uuid_d = NULL;
        size_t jobs_that_need_sessions = 0;
        uuid_t uuid;
        launch_data_t uuid_d = NULL;
        size_t jobs_that_need_sessions = 0;
-       if( d && launch_data_get_type(d) == LAUNCH_DATA_DICTIONARY ) {
+       if (d && launch_data_get_type(d) == LAUNCH_DATA_DICTIONARY) {
                launch_data_t v = launch_data_dict_lookup(d, LAUNCH_KEY_SUBMITJOB);
 
                launch_data_t v = launch_data_dict_lookup(d, LAUNCH_KEY_SUBMITJOB);
 
-               if( v && launch_data_get_type(v) == LAUNCH_DATA_ARRAY ) {
+               if (v && launch_data_get_type(v) == LAUNCH_DATA_ARRAY) {
                        size_t cnt = launch_data_array_get_count(v);
                        size_t i = 0;
 
                        uuid_generate(uuid);
                        size_t cnt = launch_data_array_get_count(v);
                        size_t i = 0;
 
                        uuid_generate(uuid);
-                       for( i = 0; i < cnt; i++ ) {
+                       for (i = 0; i < cnt; i++) {
                                launch_data_t ji = launch_data_array_get_index(v, i);
                                launch_data_t ji = launch_data_array_get_index(v, i);
-                               if( launch_data_get_type(ji) == LAUNCH_DATA_DICTIONARY ) {
+                               if (launch_data_get_type(ji) == LAUNCH_DATA_DICTIONARY) {
                                        launch_data_t existing_v = launch_data_dict_lookup(ji, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
                                        launch_data_t existing_v = launch_data_dict_lookup(ji, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
-                                       if( !existing_v ) {
+                                       if (!existing_v) {
                                                /* I really wish these were reference-counted. Sigh... */
                                                uuid_d = launch_data_new_opaque(uuid, sizeof(uuid));
                                                launch_data_dict_insert(ji, uuid_d, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
                                                jobs_that_need_sessions++;
                                                /* I really wish these were reference-counted. Sigh... */
                                                uuid_d = launch_data_new_opaque(uuid, sizeof(uuid));
                                                launch_data_dict_insert(ji, uuid_d, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
                                                jobs_that_need_sessions++;
-                                       } else if( launch_data_get_type(existing_v) == LAUNCH_DATA_OPAQUE ) {
+                                       } else if (launch_data_get_type(existing_v) == LAUNCH_DATA_OPAQUE) {
                                                jobs_that_need_sessions += uuid_data_is_null(existing_v) ? 0 : 1;
                                        }
                                }
                        }
                                                jobs_that_need_sessions += uuid_data_is_null(existing_v) ? 0 : 1;
                                        }
                                }
                        }
-               } else if( v && launch_data_get_type(v) == LAUNCH_DATA_DICTIONARY ) {
+               } else if (v && launch_data_get_type(v) == LAUNCH_DATA_DICTIONARY) {
                        launch_data_t existing_v = launch_data_dict_lookup(v, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
                        launch_data_t existing_v = launch_data_dict_lookup(v, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
-                       if( !existing_v ) {
+                       if (!existing_v) {
                                uuid_generate(uuid);
                                uuid_d = launch_data_new_opaque(uuid, sizeof(uuid));
                                launch_data_dict_insert(v, uuid_d, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
                                uuid_generate(uuid);
                                uuid_d = launch_data_new_opaque(uuid, sizeof(uuid));
                                launch_data_dict_insert(v, uuid_d, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
@@ -1108,32 +1100,32 @@ launch_msg_internal(launch_data_t d)
 
 out:
 #if !TARGET_OS_EMBEDDED
 
 out:
 #if !TARGET_OS_EMBEDDED
-       if( !uuid_is_null(uuid) && resp && jobs_that_need_sessions > 0 ) {
+       if (!uuid_is_null(uuid) && resp && jobs_that_need_sessions > 0) {
                mach_port_t session_port = _audit_session_self();
                launch_data_type_t resp_type = launch_data_get_type(resp);
                
                bool set_session = false;
                mach_port_t session_port = _audit_session_self();
                launch_data_type_t resp_type = launch_data_get_type(resp);
                
                bool set_session = false;
-               if( resp_type == LAUNCH_DATA_ERRNO ) {
+               if (resp_type == LAUNCH_DATA_ERRNO) {
                        set_session = ( launch_data_get_errno(resp) == ENEEDAUTH );
                        set_session = ( launch_data_get_errno(resp) == ENEEDAUTH );
-               } else if( resp_type == LAUNCH_DATA_ARRAY ) {
+               } else if (resp_type == LAUNCH_DATA_ARRAY) {
                        set_session = true;
                }
                
                kern_return_t kr = KERN_FAILURE;
                        set_session = true;
                }
                
                kern_return_t kr = KERN_FAILURE;
-               if( set_session ) {
+               if (set_session) {
                        kr = vproc_mig_set_security_session(bootstrap_port, uuid, session_port);
                }
                
                        kr = vproc_mig_set_security_session(bootstrap_port, uuid, session_port);
                }
                
-               if( kr == KERN_SUCCESS ) {
-                       if( resp_type == LAUNCH_DATA_ERRNO ) {
+               if (kr == KERN_SUCCESS) {
+                       if (resp_type == LAUNCH_DATA_ERRNO) {
                                launch_data_set_errno(resp, 0);
                        } else {
                                size_t i = 0;
                                launch_data_set_errno(resp, 0);
                        } else {
                                size_t i = 0;
-                               for( i = 0; i < launch_data_array_get_count(resp); i++ ) {
+                               for (i = 0; i < launch_data_array_get_count(resp); i++) {
                                        launch_data_t ri = launch_data_array_get_index(resp, i);
                                        
                                        int recvd_err = 0;
                                        launch_data_t ri = launch_data_array_get_index(resp, i);
                                        
                                        int recvd_err = 0;
-                                       if( launch_data_get_type(ri) == LAUNCH_DATA_ERRNO && (recvd_err = launch_data_get_errno(ri)) ) {
+                                       if (launch_data_get_type(ri) == LAUNCH_DATA_ERRNO && (recvd_err = launch_data_get_errno(ri))) {
                                                launch_data_set_errno(ri, recvd_err == ENEEDAUTH ? 0 : recvd_err);
                                        }
                                }
                                                launch_data_set_errno(ri, recvd_err == ENEEDAUTH ? 0 : recvd_err);
                                        }
                                }
@@ -1160,7 +1152,7 @@ launchd_msg_recv(launch_t lh, void (*cb)(launch_data_t, void *), void *context)
        int r;
 
        int fd2use = launchd_getfd(lh);
        int r;
 
        int fd2use = launchd_getfd(lh);
-       if( fd2use == -1 ) {
+       if (fd2use == -1) {
                errno = EPERM;
                return -1;
        }
                errno = EPERM;
                return -1;
        }
@@ -1287,26 +1279,6 @@ launch_data_copy(launch_data_t o)
        return r;
 }
 
        return r;
 }
 
-void
-launchd_batch_enable(bool b)
-{
-       int64_t val = b;
-
-       vproc_swap_integer(NULL, VPROC_GSK_GLOBAL_ON_DEMAND, &val, NULL);
-}
-
-bool
-launchd_batch_query(void)
-{
-       int64_t val;
-
-       if (vproc_swap_integer(NULL, VPROC_GSK_GLOBAL_ON_DEMAND, NULL, &val) == NULL) {
-               return (bool)val;
-       }
-
-       return false;
-}
-
 int
 _fd(int fd)
 {
 int
 _fd(int fd)
 {
index 5613797da7f05b00476cf4d104cfc2f09dddad8c..e6dcc34efa45d087486da09bd287a7829ed7273f 100644 (file)
@@ -36,6 +36,7 @@
 #include <assert.h>
 #include <libkern/OSAtomic.h>
 #include <sys/syscall.h>
 #include <assert.h>
 #include <libkern/OSAtomic.h>
 #include <sys/syscall.h>
+#include <sys/event.h>
 
 #if HAVE_QUARANTINE
 #include <quarantine.h>
 
 #if HAVE_QUARANTINE
 #include <quarantine.h>
@@ -48,6 +49,9 @@
 
 #include "protocol_vproc.h"
 
 
 #include "protocol_vproc.h"
 
+#include "launchd_helper.h"
+#include "launchd_helperServer.h"
+
 #include "reboot2.h"
 
 #define likely(x)      __builtin_expect((bool)(x), true)
 #include "reboot2.h"
 
 #define likely(x)      __builtin_expect((bool)(x), true)
 
 static mach_port_t get_root_bootstrap_port(void);
 
 
 static mach_port_t get_root_bootstrap_port(void);
 
-const char *__crashreporter_info__; /* this should get merged with other versions of the symbol */
+ #define _vproc_set_crash_log_message(x)
 
 static int64_t cached_pid = -1;
 static struct vproc_shmem_s *vproc_shmem;
 static pthread_once_t shmem_inited = PTHREAD_ONCE_INIT;
 static uint64_t s_cached_transactions_enabled = 0;
 
 
 static int64_t cached_pid = -1;
 static struct vproc_shmem_s *vproc_shmem;
 static pthread_once_t shmem_inited = PTHREAD_ONCE_INIT;
 static uint64_t s_cached_transactions_enabled = 0;
 
+static _vproc_transaction_callout vproc_gone2zero;
+static _vproc_transaction_callout vproc_gonenonzero;
+
+static vproc_helper_recv_ping_t vprocmgr_helper_callout;
+
 struct vproc_s {
        int32_t refcount;
        mach_port_t j_port;
 };
 
 struct vproc_s {
        int32_t refcount;
        mach_port_t j_port;
 };
 
+/* These functions are a total nightmare to get to through headers.
+ * See rdar://problem/8223092.
+ */
+typedef __darwin_mach_port_t fileport_t;
+#define FILEPORT_NULL ((fileport_t)0)
+extern int fileport_makeport(int, fileport_t *);
+extern int fileport_makefd(fileport_t);
+
 vproc_t vprocmgr_lookup_vproc(const char *label)
 {
        struct vproc_s *vp = NULL;
        
        mach_port_t mp = MACH_PORT_NULL;
        kern_return_t kr = vproc_mig_port_for_label(bootstrap_port, (char *)label, &mp);
 vproc_t vprocmgr_lookup_vproc(const char *label)
 {
        struct vproc_s *vp = NULL;
        
        mach_port_t mp = MACH_PORT_NULL;
        kern_return_t kr = vproc_mig_port_for_label(bootstrap_port, (char *)label, &mp);
-       if( kr == BOOTSTRAP_SUCCESS ) {
+       if (kr == BOOTSTRAP_SUCCESS) {
                vp = (struct vproc_s *)calloc(1, sizeof(struct vproc_s));
                vp = (struct vproc_s *)calloc(1, sizeof(struct vproc_s));
-               if( vp ) {
+               if (vp) {
                        vp->refcount = 1;
                        mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_SEND, 1);
                        vp->j_port = mp;
                }
                        vp->refcount = 1;
                        mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_SEND, 1);
                        vp->j_port = mp;
                }
-               mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_SEND, -1);
+               (void)mach_port_deallocate(mach_task_self(), mp);
        }
        
        return vp;
        }
        
        return vp;
@@ -89,9 +106,9 @@ vproc_t vprocmgr_lookup_vproc(const char *label)
 vproc_t vproc_retain(vproc_t vp)
 {
        int32_t orig = OSAtomicAdd32(1, &vp->refcount) - 1;     
 vproc_t vproc_retain(vproc_t vp)
 {
        int32_t orig = OSAtomicAdd32(1, &vp->refcount) - 1;     
-       if( orig <= 0 ) {
+       if (orig <= 0) {
                /* We've gone from 0 to 1, which means that this object was due to be freed. */
                /* We've gone from 0 to 1, which means that this object was due to be freed. */
-               __crashreporter_info__ = "Under-retain / over-release of vproc_t.";
+               _vproc_set_crash_log_message("Under-retain / over-release of vproc_t.");
                abort();
        }
        
                abort();
        }
        
@@ -101,11 +118,11 @@ vproc_t vproc_retain(vproc_t vp)
 void vproc_release(vproc_t vp)
 {
        int32_t newval = OSAtomicAdd32(-1, &vp->refcount);
 void vproc_release(vproc_t vp)
 {
        int32_t newval = OSAtomicAdd32(-1, &vp->refcount);
-       if( newval < 0 ) {
+       if (newval < 0) {
                /* We're in negative numbers, which is bad. */
                /* We're in negative numbers, which is bad. */
-               __crashreporter_info__ = "Over-release of vproc_t.";
+               _vproc_set_crash_log_message("Over-release of vproc_t.");
                abort();
                abort();
-       } else if( newval == 0 ) {
+       } else if (newval == 0) {
                mach_port_deallocate(mach_task_self(), vp->j_port);
                free(vp);
        }
                mach_port_deallocate(mach_task_self(), vp->j_port);
                free(vp);
        }
@@ -129,7 +146,7 @@ vproc_shmem_init(void)
                 * from the environment you intend to run in.
                 */
                void *_vm_addr = calloc(1, sizeof(struct vproc_shmem_s));
                 * from the environment you intend to run in.
                 */
                void *_vm_addr = calloc(1, sizeof(struct vproc_shmem_s));
-               if( !_vm_addr ) {
+               if (!_vm_addr) {
                        return;
                }
 
                        return;
                }
 
@@ -153,8 +170,8 @@ static void
 vproc_client_init(void)
 {
        char *val = getenv(LAUNCHD_DO_APPLE_INTERNAL_LOGGING);
 vproc_client_init(void)
 {
        char *val = getenv(LAUNCHD_DO_APPLE_INTERNAL_LOGGING);
-       if( val ) {
-               if( strncmp(val, "true", sizeof("true") - 1) == 0 ) {
+       if (val) {
+               if (strncmp(val, "true", sizeof("true") - 1) == 0) {
                        do_apple_internal_logging = true;
                }
        }
                        do_apple_internal_logging = true;
                }
        }
@@ -166,9 +183,7 @@ vproc_transaction_t
 vproc_transaction_begin(vproc_t vp __attribute__((unused)))
 {
        vproc_transaction_t vpt = (vproc_transaction_t)vproc_shmem_init; /* we need a "random" variable that is testable */
 vproc_transaction_begin(vproc_t vp __attribute__((unused)))
 {
        vproc_transaction_t vpt = (vproc_transaction_t)vproc_shmem_init; /* we need a "random" variable that is testable */
-#if !TARGET_OS_EMBEDDED
        _vproc_transaction_begin();
        _vproc_transaction_begin();
-#endif
 
        return vpt;
 }
 
        return vpt;
 }
@@ -176,7 +191,6 @@ vproc_transaction_begin(vproc_t vp __attribute__((unused)))
 void
 _vproc_transaction_begin(void)
 {
 void
 _vproc_transaction_begin(void)
 {
-#if !TARGET_OS_EMBEDDED
        if (unlikely(vproc_shmem == NULL)) {
                int po_r = pthread_once(&shmem_inited, vproc_client_init);
                if (po_r != 0 || vproc_shmem == NULL) {
        if (unlikely(vproc_shmem == NULL)) {
                int po_r = pthread_once(&shmem_inited, vproc_client_init);
                if (po_r != 0 || vproc_shmem == NULL) {
@@ -184,22 +198,40 @@ _vproc_transaction_begin(void)
                }
        }
 
                }
        }
 
+       /* We need to deal with the potential race condition of trying to open a
+        * transaction after launchd has marked the process for death. Consider if
+        * one thread closes the last transaction after marking the process for
+        * death. Then we call _exit(2). But exiting isn't instantaneous. So if some
+        * other threads come in very soon after and try to open transactions, we
+        * have to cut them off so that they can't begin their work. Because if they
+        * can manage to get to the point of, say, parking themselves in an
+        * uninterruptible wait, then the process won't exit.
+        *
+        * We loop here so that, if someone's calling vproc_transaction_end() at the
+        * same time, we can pick up the descent to -1 if launchd has marked us for
+        * death.
+        */
        typeof(vproc_shmem->vp_shmem_transaction_cnt) old = 0;
        do {
                old = vproc_shmem->vp_shmem_transaction_cnt;
                
                if (unlikely(old < 0)) {
        typeof(vproc_shmem->vp_shmem_transaction_cnt) old = 0;
        do {
                old = vproc_shmem->vp_shmem_transaction_cnt;
                
                if (unlikely(old < 0)) {
+                       /* No transactions should be opened after this point, so make sure
+                        * this thread can't proceed. We don't crash here because it could
+                        * be a legitimate race, as described above.
+                        */
                        if (vproc_shmem->vp_shmem_flags & VPROC_SHMEM_EXITING) {
                                _exit(0);
                        } else {
                        if (vproc_shmem->vp_shmem_flags & VPROC_SHMEM_EXITING) {
                                _exit(0);
                        } else {
-                               __crashreporter_info__ = "Unbalanced: vproc_transaction_begin()";
+                               _vproc_set_crash_log_message("Unbalanced: vproc_transaction_begin()");
                        }
                        abort();
                        }
                        abort();
+               } else if (old == 0 && vproc_gonenonzero) {
+                       vproc_gonenonzero();
                }
                }
-       } while( !__sync_bool_compare_and_swap(&vproc_shmem->vp_shmem_transaction_cnt, old, old + 1) );
+       } while (!__sync_bool_compare_and_swap(&vproc_shmem->vp_shmem_transaction_cnt, old, old + 1));
        
        runtime_ktrace(RTKT_VPROC_TRANSACTION_INCREMENT, old + 1, 0, 0);
        
        runtime_ktrace(RTKT_VPROC_TRANSACTION_INCREMENT, old + 1, 0, 0);
-#endif
 }
 
 size_t
 }
 
 size_t
@@ -238,7 +270,7 @@ _vproc_transaction_count_for_pid(pid_t p, int32_t *count, bool *condemned)
 {
        boolean_t _condemned = false;
        kern_return_t kr = vproc_mig_transaction_count_for_pid(bootstrap_port, p, count, &_condemned);
 {
        boolean_t _condemned = false;
        kern_return_t kr = vproc_mig_transaction_count_for_pid(bootstrap_port, p, count, &_condemned);
-       if( kr == KERN_SUCCESS && condemned ) {
+       if (kr == KERN_SUCCESS && condemned) {
                *condemned = _condemned ? true : false;
        }
        
                *condemned = _condemned ? true : false;
        }
        
@@ -246,9 +278,9 @@ _vproc_transaction_count_for_pid(pid_t p, int32_t *count, bool *condemned)
 }
 
 void
 }
 
 void
-#if !TARGET_OS_EMBEDDED
 _vproc_transaction_try_exit(int status)
 {
 _vproc_transaction_try_exit(int status)
 {
+#if !TARGET_OS_EMBEDDED
        if (unlikely(vproc_shmem == NULL)) {
                return;
        }
        if (unlikely(vproc_shmem == NULL)) {
                return;
        }
@@ -257,31 +289,25 @@ _vproc_transaction_try_exit(int status)
                vproc_shmem->vp_shmem_flags |= VPROC_SHMEM_EXITING;
                _exit(status);
        }
                vproc_shmem->vp_shmem_flags |= VPROC_SHMEM_EXITING;
                _exit(status);
        }
-}
 #else
 #else
-_vproc_transaction_try_exit(int status __attribute__((unused)))
-{
        
        
-}
 #endif
 #endif
+}
 
 void
 vproc_transaction_end(vproc_t vp __attribute__((unused)), vproc_transaction_t vpt)
 {
        if (unlikely(vpt != (vproc_transaction_t)vproc_shmem_init)) {
 
 void
 vproc_transaction_end(vproc_t vp __attribute__((unused)), vproc_transaction_t vpt)
 {
        if (unlikely(vpt != (vproc_transaction_t)vproc_shmem_init)) {
-               __crashreporter_info__ = "Bogus transaction handle passed to vproc_transaction_end() ";
+               _vproc_set_crash_log_message("Bogus transaction handle passed to vproc_transaction_end() ");
                abort();
        }
 
                abort();
        }
 
-#if !TARGET_OS_EMBEDDED
        _vproc_transaction_end();
        _vproc_transaction_end();
-#endif
 }
 
 void
 _vproc_transaction_end(void)
 {
 }
 
 void
 _vproc_transaction_end(void)
 {
-#if !TARGET_OS_EMBEDDED
        typeof(vproc_shmem->vp_shmem_transaction_cnt) newval;
 
        if (unlikely(vproc_shmem == NULL)) {
        typeof(vproc_shmem->vp_shmem_transaction_cnt) newval;
 
        if (unlikely(vproc_shmem == NULL)) {
@@ -295,11 +321,12 @@ _vproc_transaction_end(void)
                if (vproc_shmem->vp_shmem_flags & VPROC_SHMEM_EXITING) {
                        _exit(0);
                } else {
                if (vproc_shmem->vp_shmem_flags & VPROC_SHMEM_EXITING) {
                        _exit(0);
                } else {
-                       __crashreporter_info__ = "Unbalanced: vproc_transaction_end()";
+                       _vproc_set_crash_log_message("Unbalanced: vproc_transaction_end()");
                }
                abort();
                }
                abort();
+       } else if (newval == 0 && vproc_gone2zero) {
+               vproc_gone2zero();
        }
        }
-#endif
 }
 
 vproc_standby_t
 }
 
 vproc_standby_t
@@ -332,7 +359,7 @@ _vproc_standby_begin(void)
        newval = __sync_add_and_fetch(&vproc_shmem->vp_shmem_standby_cnt, 1);
 
        if (unlikely(newval < 1)) {
        newval = __sync_add_and_fetch(&vproc_shmem->vp_shmem_standby_cnt, 1);
 
        if (unlikely(newval < 1)) {
-               __crashreporter_info__ = "Unbalanced: vproc_standby_begin()";
+               _vproc_set_crash_log_message("Unbalanced: vproc_standby_begin()");
                abort();
        }
 #else
                abort();
        }
 #else
@@ -345,7 +372,7 @@ vproc_standby_end(vproc_t vp __attribute__((unused)), vproc_standby_t vpt __attr
 {
 #ifdef VPROC_STANDBY_IMPLEMENTED
        if (unlikely(vpt != (vproc_standby_t)vproc_shmem_init)) {
 {
 #ifdef VPROC_STANDBY_IMPLEMENTED
        if (unlikely(vpt != (vproc_standby_t)vproc_shmem_init)) {
-               __crashreporter_info__ = "Bogus standby handle passed to vproc_standby_end() ";
+               _vproc_set_crash_log_message("Bogus standby handle passed to vproc_standby_end() ");
                abort();
        }
 
                abort();
        }
 
@@ -361,15 +388,15 @@ _vproc_standby_end(void)
 #ifdef VPROC_STANDBY_IMPLEMENTED
        typeof(vproc_shmem->vp_shmem_standby_cnt) newval;
 
 #ifdef VPROC_STANDBY_IMPLEMENTED
        typeof(vproc_shmem->vp_shmem_standby_cnt) newval;
 
-       if( unlikely(vproc_shmem == NULL) ) {
-               __crashreporter_info__ = "Process called vproc_standby_end() when not enrolled in transaction model.";
+       if (unlikely(vproc_shmem == NULL)) {
+               _vproc_set_crash_log_message("Process called vproc_standby_end() when not enrolled in transaction model.");
                abort();
        }
 
        newval = __sync_sub_and_fetch(&vproc_shmem->vp_shmem_standby_cnt, 1);
 
        if (unlikely(newval < 0)) {
                abort();
        }
 
        newval = __sync_sub_and_fetch(&vproc_shmem->vp_shmem_standby_cnt, 1);
 
        if (unlikely(newval < 0)) {
-               __crashreporter_info__ = "Unbalanced: vproc_standby_end()";
+               _vproc_set_crash_log_message("Unbalanced: vproc_standby_end()");
                abort();
        }
 #else
                abort();
        }
 #else
@@ -377,6 +404,34 @@ _vproc_standby_end(void)
 #endif
 }
 
 #endif
 }
 
+int32_t *
+_vproc_transaction_ptr(void)
+{
+       return NULL;
+}
+
+void
+_vproc_transaction_set_callouts(_vproc_transaction_callout gone2zero, _vproc_transaction_callout gonenonzero)
+{
+       if (unlikely(vproc_shmem == NULL)) {
+               int po_r = pthread_once(&shmem_inited, vproc_client_init);
+               if (po_r != 0 || vproc_shmem == NULL) {
+                       return;
+               }
+       }
+
+       static bool once = false;
+       if (once) {
+               _vproc_set_crash_log_message("This SPI may only be called once. It is only meant for libxpc.");
+               abort();
+       }
+
+       once = true;
+
+       vproc_gone2zero = gone2zero;
+       vproc_gonenonzero = gonenonzero;
+}
+
 kern_return_t
 _vproc_grab_subset(mach_port_t bp, mach_port_t *reqport, mach_port_t *rcvright, launch_data_t *outval,
                mach_port_array_t *ports, mach_msg_type_number_t *portCnt)
 kern_return_t
 _vproc_grab_subset(mach_port_t bp, mach_port_t *reqport, mach_port_t *rcvright, launch_data_t *outval,
                mach_port_array_t *ports, mach_msg_type_number_t *portCnt)
@@ -413,7 +468,7 @@ _vproc_post_fork_ping(void)
        do {
                mach_port_t session = MACH_PORT_NULL;
                kern_return_t kr = vproc_mig_post_fork_ping(bootstrap_port, mach_task_self(), &session);
        do {
                mach_port_t session = MACH_PORT_NULL;
                kern_return_t kr = vproc_mig_post_fork_ping(bootstrap_port, mach_task_self(), &session);
-               if( kr != KERN_SUCCESS ) {
+               if (kr != KERN_SUCCESS) {
                        /* If this happens, our bootstrap port probably got hosed. */
                        _vproc_log(LOG_ERR, "Post-fork ping failed!");
                        break;
                        /* If this happens, our bootstrap port probably got hosed. */
                        _vproc_log(LOG_ERR, "Post-fork ping failed!");
                        break;
@@ -422,19 +477,19 @@ _vproc_post_fork_ping(void)
                /* If we get back MACH_PORT_NULL, that means we just stick with the session
                 * we inherited across fork(2).
                 */
                /* If we get back MACH_PORT_NULL, that means we just stick with the session
                 * we inherited across fork(2).
                 */
-               if( session == MACH_PORT_NULL ) {
+               if (session == MACH_PORT_NULL) {
                        s = ~AU_DEFAUDITSID;
                        break;
                }
                
                s = _audit_session_join(session);
                        s = ~AU_DEFAUDITSID;
                        break;
                }
                
                s = _audit_session_join(session);
-               if( s == 0 ) {
+               if (s == 0) {
                        _vproc_log_error(LOG_ERR, "Could not join security session!");
                        s = AU_DEFAUDITSID;
                } else {
                        _vproc_log(LOG_DEBUG, "Joined session %d.", s);
                }
                        _vproc_log_error(LOG_ERR, "Could not join security session!");
                        s = AU_DEFAUDITSID;
                } else {
                        _vproc_log(LOG_DEBUG, "Joined session %d.", s);
                }
-       } while( 0 );
+       } while (0);
        
        return s != AU_DEFAUDITSID ? NULL : _vproc_post_fork_ping;
 #else
        
        return s != AU_DEFAUDITSID ? NULL : _vproc_post_fork_ping;
 #else
@@ -485,7 +540,7 @@ _vprocmgr_move_subset_to_user(uid_t target_user, const char *session_type, uint6
                return (vproc_err_t)_vprocmgr_move_subset_to_user;
        }
        
                return (vproc_err_t)_vprocmgr_move_subset_to_user;
        }
        
-       if( is_bkgd ) {         
+       if (is_bkgd) {          
                task_set_bootstrap_port(mach_task_self(), puc);
                mach_port_deallocate(mach_task_self(), bootstrap_port);
                bootstrap_port = puc;
                task_set_bootstrap_port(mach_task_self(), puc);
                mach_port_deallocate(mach_task_self(), bootstrap_port);
                bootstrap_port = puc;
@@ -511,7 +566,7 @@ _vprocmgr_switch_to_session(const char *target_session, vproc_flags_t flags __at
 
        mach_port_t tnp = MACH_PORT_NULL;
        task_name_for_pid(mach_task_self(), getpid(), &tnp);
 
        mach_port_t tnp = MACH_PORT_NULL;
        task_name_for_pid(mach_task_self(), getpid(), &tnp);
-       if( (kr = vproc_mig_switch_to_session(bootstrap_port, tnp, (char *)target_session, _audit_session_self(), &new_bsport)) != KERN_SUCCESS ) {
+       if ((kr = vproc_mig_switch_to_session(bootstrap_port, tnp, (char *)target_session, _audit_session_self(), &new_bsport)) != KERN_SUCCESS) {
                _vproc_log(LOG_NOTICE, "_vprocmgr_switch_to_session(): kr = 0x%x", kr);
                return (vproc_err_t)_vprocmgr_switch_to_session;
        }
                _vproc_log(LOG_NOTICE, "_vprocmgr_switch_to_session(): kr = 0x%x", kr);
                return (vproc_err_t)_vprocmgr_switch_to_session;
        }
@@ -568,6 +623,7 @@ _spawn_via_launchd(const char *label, const char *const *argv, const struct spaw
        launch_data_dict_insert(in_obj, tmp_array, LAUNCH_JOBKEY_PROGRAMARGUMENTS);
 
        if (spawn_attrs) switch (struct_version) {
        launch_data_dict_insert(in_obj, tmp_array, LAUNCH_JOBKEY_PROGRAMARGUMENTS);
 
        if (spawn_attrs) switch (struct_version) {
+       case 3:
        case 2:
 #if HAVE_QUARANTINE
                if (spawn_attrs->spawn_quarantine) {
        case 2:
 #if HAVE_QUARANTINE
                if (spawn_attrs->spawn_quarantine) {
@@ -607,6 +663,18 @@ _spawn_via_launchd(const char *label, const char *const *argv, const struct spaw
                        tmp = launch_data_new_bool(true);
                        launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_WAITFORDEBUGGER);
                }
                        tmp = launch_data_new_bool(true);
                        launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_WAITFORDEBUGGER);
                }
+               if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_TALAPP) {
+                       tmp = launch_data_new_string(LAUNCH_KEY_POSIXSPAWNTYPE_TALAPP);
+                       launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_POSIXSPAWNTYPE);
+               }
+               if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_WIDGET) {
+                       tmp = launch_data_new_string(LAUNCH_KEY_POSIXSPAWNTYPE_WIDGET);
+                       launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_POSIXSPAWNTYPE);
+               }
+               if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_DISABLE_ASLR) {
+                       tmp = launch_data_new_bool(true);
+                       launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_DISABLEASLR);
+               }
 
                if (spawn_attrs->spawn_env) {
                        launch_data_t tmp_dict = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
 
                if (spawn_attrs->spawn_env) {
                        launch_data_t tmp_dict = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
@@ -660,13 +728,19 @@ _spawn_via_launchd(const char *label, const char *const *argv, const struct spaw
 
        indata = (vm_offset_t)buf;
 
 
        indata = (vm_offset_t)buf;
 
-       kr = vproc_mig_spawn(bootstrap_port, indata, indata_cnt, _audit_session_self(), &p, &obsvr_port);
+       if (struct_version == 3) {
+               kr = vproc_mig_spawn2(bootstrap_port, indata, indata_cnt, _audit_session_self(), &p, &obsvr_port); 
+       } else {
+               _vproc_set_crash_log_message("Bogus version passed to _spawn_via_launchd(). For this release, the only valid version is 3.");
+       }
 
        if (kr == VPROC_ERR_TRY_PER_USER) {
                mach_port_t puc;
 
                if (vproc_mig_lookup_per_user_context(bootstrap_port, 0, &puc) == 0) {
 
        if (kr == VPROC_ERR_TRY_PER_USER) {
                mach_port_t puc;
 
                if (vproc_mig_lookup_per_user_context(bootstrap_port, 0, &puc) == 0) {
-                       kr = vproc_mig_spawn(puc, indata, indata_cnt, _audit_session_self(), &p, &obsvr_port);
+                       if (struct_version == 3) {
+                               kr = vproc_mig_spawn2(puc, indata, indata_cnt, _audit_session_self(), &p, &obsvr_port);
+                       }
                        mach_port_deallocate(mach_task_self(), puc);
                }
        }
                        mach_port_deallocate(mach_task_self(), puc);
                }
        }
@@ -685,7 +759,11 @@ out:
                if (spawn_attrs && spawn_attrs->spawn_observer_port) {
                        *spawn_attrs->spawn_observer_port = obsvr_port;
                } else {
                if (spawn_attrs && spawn_attrs->spawn_observer_port) {
                        *spawn_attrs->spawn_observer_port = obsvr_port;
                } else {
-                       mach_port_deallocate(mach_task_self(), obsvr_port);
+                       if (struct_version == 3) {
+                               mach_port_mod_refs(mach_task_self(), obsvr_port, MACH_PORT_RIGHT_RECEIVE, -1);
+                       } else {
+                               mach_port_deallocate(mach_task_self(), obsvr_port);
+                       }
                }
                return p;
        case BOOTSTRAP_NOT_PRIVILEGED:
                }
                return p;
        case BOOTSTRAP_NOT_PRIVILEGED:
@@ -704,15 +782,16 @@ out:
 }
 
 kern_return_t
 }
 
 kern_return_t
-mpm_wait(mach_port_t ajob, int *wstatus)
+mpm_wait(mach_port_t ajob __attribute__((unused)), int *wstatus)
 {
 {
-       return vproc_mig_wait(ajob, wstatus);
+       *wstatus = 0;
+       return 0;
 }
 
 kern_return_t
 }
 
 kern_return_t
-mpm_uncork_fork(mach_port_t ajob)
+mpm_uncork_fork(mach_port_t ajob __attribute__((unused)))
 {
 {
-       return vproc_mig_uncork_fork(ajob);
+       return KERN_FAILURE;
 }
 
 kern_return_t
 }
 
 kern_return_t
@@ -823,17 +902,17 @@ vproc_swap_integer(vproc_t vp, vproc_gsk_t key, int64_t *inval, int64_t *outval)
                break;
        case VPROC_GSK_TRANSACTIONS_ENABLED:
                /* Shared memory region is required for transactions. */
                break;
        case VPROC_GSK_TRANSACTIONS_ENABLED:
                /* Shared memory region is required for transactions. */
-               if( unlikely(vproc_shmem == NULL) ) {
+               if (unlikely(vproc_shmem == NULL)) {
                        int po_r = pthread_once(&shmem_inited, vproc_client_init);
                        int po_r = pthread_once(&shmem_inited, vproc_client_init);
-                       if( po_r != 0 || vproc_shmem == NULL ) {
-                               if( outval ) {
+                       if (po_r != 0 || vproc_shmem == NULL) {
+                               if (outval) {
                                        *outval = -1;
                                }
                                return (vproc_err_t)vproc_swap_integer;
                        }
                }
        
                                        *outval = -1;
                                }
                                return (vproc_err_t)vproc_swap_integer;
                        }
                }
        
-               if( s_cached_transactions_enabled && outval ) {
+               if (s_cached_transactions_enabled && outval) {
                        *outval = s_cached_transactions_enabled;
                        return NULL;
                }
                        *outval = s_cached_transactions_enabled;
                        return NULL;
                }
@@ -853,21 +932,21 @@ vproc_swap_integer(vproc_t vp, vproc_gsk_t key, int64_t *inval, int64_t *outval)
                        cached_is_managed = outval ? *outval : dummyval;
                        break;
                case VPROC_GSK_TRANSACTIONS_ENABLED:
                        cached_is_managed = outval ? *outval : dummyval;
                        break;
                case VPROC_GSK_TRANSACTIONS_ENABLED:
-                       /* Once you're in the transaction model, you're in for good. Like the Mafia. */
                        s_cached_transactions_enabled = 1;
                        break;
                        s_cached_transactions_enabled = 1;
                        break;
-               case VPROC_GSK_PERUSER_SUSPEND: {
-                       char peruser_label[NAME_MAX];
-                       snprintf(peruser_label, NAME_MAX - 1, "com.apple.launchd.peruser.%u", (uid_t)*inval);
-                       
-                       vproc_t pu_vp = vprocmgr_lookup_vproc(peruser_label);
-                       if( pu_vp ) {
-                               int status = 0;
-                               kr = vproc_mig_wait2(bootstrap_port, pu_vp->j_port, &status, false);
-                               vproc_release(pu_vp);
+               case VPROC_GSK_PERUSER_SUSPEND:
+                       if (dummyval) {
+                               /* Wait for the per-user launchd to exit before returning. */
+                               int kq = kqueue();
+                               struct kevent kev;
+                               EV_SET(&kev, dummyval, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, 0);
+                               int r = kevent(kq, &kev, 1, &kev, 1, NULL);
+                               (void)close(kq);
+                               if (r != 1) {
+                                       return NULL;
+                               }
+                               break;
                        }
                        }
-                       break;
-               }
                default:
                        break;
                }
                default:
                        break;
                }
@@ -959,15 +1038,15 @@ vproc_swap_string(vproc_t vp, vproc_gsk_t key, const char *instr, char **outstr)
        launch_data_t outstr_data = NULL;
        
        vproc_err_t verr = vproc_swap_complex(vp, key, instr_data, &outstr_data);
        launch_data_t outstr_data = NULL;
        
        vproc_err_t verr = vproc_swap_complex(vp, key, instr_data, &outstr_data);
-       if( !verr && outstr ) {
-               if( launch_data_get_type(outstr_data) == LAUNCH_DATA_STRING ) {
+       if (!verr && outstr) {
+               if (launch_data_get_type(outstr_data) == LAUNCH_DATA_STRING) {
                        *outstr = strdup(launch_data_get_string(outstr_data));
                } else {
                        verr = (vproc_err_t)vproc_swap_string;
                }
                launch_data_free(outstr_data);
        }
                        *outstr = strdup(launch_data_get_string(outstr_data));
                } else {
                        verr = (vproc_err_t)vproc_swap_string;
                }
                launch_data_free(outstr_data);
        }
-       if( instr_data ) {
+       if (instr_data) {
                launch_data_free(instr_data);
        }
        
                launch_data_free(instr_data);
        }
        
@@ -985,37 +1064,19 @@ reboot2(uint64_t flags)
 }
 
 vproc_err_t
 }
 
 vproc_err_t
-_vproc_kickstart_by_label(const char *label, pid_t *out_pid, mach_port_t *out_port_name, mach_port_t *out_obsrvr_port, vproc_flags_t flags)
+_vproc_kickstart_by_label(const char *label, pid_t *out_pid, mach_port_t *out_port_name __attribute__((unused)), mach_port_t *out_obsrvr_port __attribute__((unused)), vproc_flags_t flags)
 {
 {
-       mach_port_t junk = MACH_PORT_NULL;
-       mach_port_t junk2 = MACH_PORT_NULL;
-       
-       kern_return_t kr = vproc_mig_kickstart(bootstrap_port, (char *)label, out_pid, out_port_name ?: &junk, out_obsrvr_port ?: &junk2, flags);
-       if( kr == KERN_SUCCESS ) {
-               if( !out_port_name ) {
-                       mach_port_mod_refs(mach_task_self(), junk, MACH_PORT_RIGHT_SEND, -1);
-               }
-               
-               if( !out_obsrvr_port ) {
-                       mach_port_mod_refs(mach_task_self(), junk2, MACH_PORT_RIGHT_SEND, -1);
-               }
-               
+       /* Ignore the two port parameters. This SPI isn't long for this world, and
+        * all the current clients just leak them anyway.
+        */
+       kern_return_t kr = vproc_mig_kickstart(bootstrap_port, (char *)label, out_pid, flags);
+       if (kr == KERN_SUCCESS) {
                return NULL;
        }
 
        return (vproc_err_t)_vproc_kickstart_by_label;
 }
 
                return NULL;
        }
 
        return (vproc_err_t)_vproc_kickstart_by_label;
 }
 
-vproc_err_t
-_vproc_wait_by_label(const char *label, int *out_wstatus)
-{
-       if (vproc_mig_embedded_wait(bootstrap_port, (char *)label, out_wstatus) == 0) {
-               return NULL;
-       }
-
-       return (vproc_err_t)_vproc_wait_by_label;
-}
-
 vproc_err_t
 _vproc_set_global_on_demand(bool state)
 {
 vproc_err_t
 _vproc_set_global_on_demand(bool state)
 {
@@ -1058,3 +1119,84 @@ _vproc_log_error(int pri, const char *msg, ...)
        _vproc_logv(pri, saved_errno, msg, ap);
        va_end(ap);
 }
        _vproc_logv(pri, saved_errno, msg, ap);
        va_end(ap);
 }
+
+bool
+vprocmgr_helper_check_in(const char *name, mach_port_t rp, launch_data_t *events, uint64_t *tokens)
+{
+       vm_offset_t events_packed = 0;
+       mach_msg_type_number_t sz = 0;
+       size_t data_off = 0;
+       
+       kern_return_t kr = vproc_mig_event_source_check_in(bootstrap_port, (char *)name, rp, &events_packed, &sz, tokens);
+       if (kr == 0) {
+               launch_data_t _events = launch_data_unpack((void *)events_packed, sz, NULL, 0, &data_off, 0);
+               *events = launch_data_copy(_events);
+               if (!*events) {
+                       kr = 1;
+               }
+               
+               mig_deallocate(events_packed, sz);
+       }
+       
+       return (kr == 0);
+}
+
+bool
+vprocmgr_helper_event_set_state(const char *sysname, uint64_t token, bool state)
+{
+       kern_return_t kr = vproc_mig_event_set_state(bootstrap_port, (char *)sysname, token, state);
+       return (kr == 0);
+}
+
+void
+vprocmgr_helper_register(vproc_helper_recv_ping_t callout)
+{
+       vprocmgr_helper_callout = callout;
+}
+
+/* The type naming convention is as follows:
+ * For requests...
+ *     union __RequestUnion__<userprefix><subsystem>_subsystem
+ * For replies...
+ *     union __ReplyUnion__<userprefix><subsystem>_subsystem
+ */
+union maxmsgsz {
+       union __RequestUnion__helper_downcall_launchd_helper_subsystem req;
+       union __ReplyUnion__helper_downcall_launchd_helper_subsystem rep;
+};
+
+size_t vprocmgr_helper_maxmsgsz = sizeof(union maxmsgsz);
+
+kern_return_t
+helper_recv_ping(mach_port_t p, audit_token_t autok)
+{
+       return vprocmgr_helper_callout(p, autok);
+}
+
+boolean_t
+vprocmgr_helper_server_routine_for_dispatch(mach_msg_header_t *message, mach_msg_header_t *reply)
+{
+       return launchd_helper_server(message, reply);
+}
+
+kern_return_t
+helper_recv_wait(mach_port_t p, int status)
+{
+       /* Total hack. */
+       return (errno = mach_port_set_context(mach_task_self(), p, (mach_vm_address_t)status));
+}
+
+int
+launch_wait(mach_port_t port)
+{
+       int status = -1;
+       errno = mach_msg_server_once(launchd_helper_server, vprocmgr_helper_maxmsgsz, port, 0);
+       if (errno == MACH_MSG_SUCCESS) {
+               mach_vm_address_t ctx = 0;
+               if ((errno = mach_port_get_context(mach_task_self(), port, &ctx)) == KERN_SUCCESS) {
+                       status = ctx;
+               }
+       }
+
+       return status;
+}
index 8d7e72f92d7d33fa522fa1fd29f081c9c142faaa..92ec153ead5ed06288d62b6063210ce5fb5a5a64 100644 (file)
@@ -38,16 +38,21 @@ skip; /* check_in */
 
 skip; /* register2 */
 
 
 skip; /* register2 */
 
-simpleroutine look_up2_forward(
-                               __bs_port                               : job_t;
-replyport              __rport                                 : mach_port_move_send_once_t;
-                               __service_name                  : name_t;
-                               __target_pid                    : pid_t;
-                               __flags                                 : uint64_t);
+simpleroutine
+look_up2_forward(
+                               j                               : job_t;
+replyport              rp                              : mach_port_move_send_once_t;
+                               servicename             : name_t;
+                               targetpid               : pid_t;
+                               instanceid              : uuid_t;
+                               flags                   : uint64_t
+);
 
 skip; /* send_signal */
 
 
 skip; /* send_signal */
 
-simpleroutine parent_forward(
-                __bs_port                              : job_t;
-replyport              __rport                                 : mach_port_move_send_once_t);
+simpleroutine
+parent_forward(
+                j                              : job_t;
+replyport              rp                              : mach_port_move_send_once_t
+);
 
 
index fd53cfbda5f802ae5aca448e3d49bbfa507500fa..8d805f5846c471bdc1af4ac1b8c767416fcbf3f2 100644 (file)
@@ -37,9 +37,11 @@ skip; /* register */
 
 skip; /* look_up */
 
 
 skip; /* look_up */
 
-simpleroutine job_mig_send_signal_reply(
-               __r_port        : mach_port_move_send_once_t;
-               __result        : kern_return_t, RetCode);
+simpleroutine
+job_mig_send_signal_reply(
+               rp              : mach_port_move_send_once_t;
+               kr              : kern_return_t, RetCode
+);
 
 skip; /* parent */
 
 
 skip; /* parent */
 
@@ -57,10 +59,7 @@ skip; /* getsocket */
 
 skip; /* spawn */
 
 
 skip; /* spawn */
 
-simpleroutine job_mig_wait_reply(
-               __r_port        : mach_port_move_send_once_t;
-               __result        : kern_return_t, RetCode;
-               __wait          : integer_t);
+skip; /* wait */
 
 skip; /* uncork_fork */
 
 
 skip; /* uncork_fork */
 
@@ -74,10 +73,12 @@ skip; /* move_subset */
 
 skip; /* swap_complex */
 
 
 skip; /* swap_complex */
 
-simpleroutine job_mig_log_drain_reply(
-               __r_port        : mach_port_move_send_once_t;
-               __result        : kern_return_t, RetCode;
-               __outval        : pointer_t);
+simpleroutine 
+job_mig_log_drain_reply(
+               rp              : mach_port_move_send_once_t;
+               kr              : kern_return_t, RetCode;
+               outval  : pointer_t
+);
 
 skip; /* log_forward */
 
 
 skip; /* log_forward */
 
@@ -97,8 +98,20 @@ skip; /* port_for_label */
 
 skip; /* init_session */
 
 
 skip; /* init_session */
 
-simpleroutine job_mig_wait2_reply(
-               __r_port        : mach_port_move_send_once_t;
-               __result        : kern_return_t, RetCode;
-               __waitval       : integer_t;
-               __legacy        : boolean_t);
+skip; /* set_security_session */
+
+skip; /* wait2 */
+
+skip; /* event_source_check_in */
+
+skip; /* event_set_state */
+
+simpleroutine
+job_mig_spawn2_reply(
+               rp              : mach_port_move_send_once_t;
+               kr              : kern_return_t, RetCode;
+               pid             : pid_t;
+               obsrvp  : mach_port_move_receive_t
+);
+
+skip; /* get_root_bootstrap */
index ef28589382674666e5a35ea0266a723705ee302e..702f9fd53c84aa7a6b5cedb36935d1e7e6634712 100644 (file)
@@ -38,192 +38,264 @@ type mach_port_move_send_array_t = array[] of mach_port_move_send_t
 userprefix vproc_mig_;
 serverprefix job_mig_;
 
 userprefix vproc_mig_;
 serverprefix job_mig_;
 
-routine create_server(
-                               __bs_port                       : job_t;
-                               __server_cmd            : cmd_t;
-                               __server_uid            : uid_t;
-                               __on_demand                     : boolean_t;
-out                            __server_port           : mach_port_make_send_t);
-
-routine reboot2(
-                               __bs_port                       : job_t;
-                               __flags                         : uint64_t);
-
-routine check_in2(
-                               __bs_port                       : job_t;
-                               __service_name          : name_t;
-out                            __service_port          : mach_port_move_receive_t;
-                               __flags                         : uint64_t);
-
-routine register2(
-                               __bs_port                       : job_t;
-                               __service_name          : name_t;
-                               __service_port          : mach_port_t;
-                               __flags                         : uint64_t);
-
-routine look_up2(
-                               __bs_port                       : job_t;
-sreplyport             __rport                         : mach_port_make_send_once_t;
-                               __service_name          : name_t;
-out                            __service_port          : mach_port_t;
-UserAuditToken __server_cred           : audit_token_t;
-                               __target_pid            : pid_t;
-                               __flags                         : uint64_t);
-
-routine send_signal(
-                               __bs_port                       : job_t;
-sreplyport             __rport                         : mach_port_make_send_once_t;
-                               __label                         : name_t;
-                               __signal                        : integer_t);
-
-routine parent(
-                               __bs_port                       : job_t;
-sreplyport             __rport                         : mach_port_make_send_once_t;
-out                            __parent_port           : mach_port_make_send_t);
-
-routine post_fork_ping(
-                               __bs_port                       : job_t;
-                               __task_port                     : task_t;
-out                            __audit_session         : mach_port_t);
-
-routine info(
-                               __bs_port                       : job_t;
-out                            __service_names         : name_array_t, dealloc;
-out                            __service_jobs          : name_array_t, dealloc;
-out                            __service_active        : bootstrap_status_array_t, dealloc;
-                               __flags                         : uint64_t);
-
-routine subset(
-                               __bs_port                       : job_t;
-                               __requestor_port        : mach_port_t;
-out                            __subset_port           : mach_port_make_send_t);
-
-routine setup_shmem(
-                               __bs_port                       : job_t;
-out                            __shmem_port            : mach_port_move_send_t);
-
-routine take_subset(
-                               __bs_port                       : job_t;
-out                            __bs_reqport            : mach_port_move_send_t;
-out                            __bs_rcvright           : mach_port_move_receive_t;
-out                            __outdata                       : pointer_t, dealloc;
-out                            __service_ports         : mach_port_move_send_array_t, dealloc);
-
-routine getsocket(
-                               __bs_port                       : job_t;
-out                            __sockpath                      : name_t);
-
-routine spawn(
-                               __bs_port                       : job_t;
-                               __indata                        : pointer_t;
-                               __audit_session         : mach_port_t;
-out                            __pid                           : pid_t;
-out                            __obsvr_port            : mach_port_make_send_t);
-
-routine wait(
-                               __bs_port                       : job_t;
-sreplyport             __rport                         : mach_port_make_send_once_t;
-out                            __waitval                       : integer_t);
-
-routine uncork_fork(
-                               __bs_port                       : job_t);
-
-routine swap_integer(
-                               __bs_port                       : job_t;
-                               __inkey                         : vproc_gsk_t;
-                               __outkey                        : vproc_gsk_t;
-                               __inval                         : int64_t;
-out                            __outval                        : int64_t);
-
-routine log(
-                               __bs_port                       : job_t;
-                               __pri                           : integer_t;
-                               __err                           : integer_t;
-                               __msg                           : logmsg_t);
-
-routine lookup_per_user_context(
-                               __bs_port                       : job_t;
-                               __wu                            : uid_t;
-out                            __u_cont                        : mach_port_t);
-
-routine move_subset(
-                               __bs_port                       : job_t;
-                               __target_port           : mach_port_t;
-                               __sessiontype           : name_t;
-                               __audit_session         : mach_port_t;
-                               __sessionflags          : uint64_t);
-
-routine swap_complex(
-                               __bs_port                       : job_t;
-                               __inkey                         : vproc_gsk_t;
-                               __outkey                        : vproc_gsk_t;
-                               __inval                         : pointer_t;
-out                            __outval                        : pointer_t, dealloc);
-
-routine log_drain(
-                               __bs_port                       : job_t;
-sreplyport             __rport                         : mach_port_make_send_once_t;
-out                            __outval                        : pointer_t, dealloc);
-
-routine log_forward(
-                               __bs_port                       : job_t;
-                               __inval                         : pointer_t);
-
-routine kickstart(
-                               __bs_port                       : job_t;
-                               __label                         : name_t;
-out                            __pid                           : pid_t;
-out                            __name_port                     : mach_port_t;
-out                            __obsrvr_port           : mach_port_make_send_t;
-                               __flags                         : natural_t);
-
-routine embedded_wait(
-                               __bs_port                       : job_t;
-                               __label                         : name_t;
-out                            __waitval                       : integer_t);
-
-routine lookup_children(
-                               __bs_port                       : job_t;
-out                    __child_ports           : mach_port_move_send_array_t, dealloc;
-out                            __child_names           : name_array_t, dealloc;
-out                            __child_properties      : bootstrap_property_array_t, dealloc);
-
-routine switch_to_session(
-                               __bs_port                       : job_t;
-                               __req_port                      : mach_port_t;
-                               __session_name          : name_t;
-                               __audit_session         : mach_port_t;
-out                            __new_bs_port           : mach_port_make_send_t);
-
-routine transaction_count_for_pid(
-                               __bs_port                       : job_t;
-                               __pid                           : pid_t;
-out                            __cnt                           : integer_t;
-out                            __condemend                     : boolean_t);
+routine
+create_server(
+                               j                       : job_t;
+                               servercmd       : cmd_t;
+                               serveruid       : uid_t;
+                               ondemand        : boolean_t;
+out                            serverport      : mach_port_make_send_t
+);
+
+routine
+reboot2(
+                               j                       : job_t;
+                               flags           : uint64_t
+);
+
+routine
+check_in2(
+                               j                       : job_t;
+                               servicename     : name_t;
+out                            serviceport     : mach_port_move_receive_t;
+out                            instanceid      : uuid_t;
+                               flags           : uint64_t
+);
+
+routine
+register2(
+                               j                       : job_t;
+                               servicename     : name_t;
+                               serviceport     : mach_port_t;
+                               flags           : uint64_t
+);
+
+routine
+look_up2(
+                               j                       : job_t;
+sreplyport             rp                      : mach_port_make_send_once_t;
+                               servicename     : name_t;
+out                            serviceport     : mach_port_t;
+UserAuditToken servercreds     : audit_token_t;
+                               targetpid       : pid_t;
+                               instanceid      : uuid_t;
+                               flags           : uint64_t
+);
+
+routine
+send_signal(
+                               j                       : job_t;
+sreplyport             rp                      : mach_port_make_send_once_t;
+                               label           : name_t;
+                               sig                     : integer_t
+);
+
+routine
+parent(
+                               j                       : job_t;
+sreplyport             rp                      : mach_port_make_send_once_t;
+out                            parentport      : mach_port_make_send_t
+);
+
+routine
+post_fork_ping(
+                               j                       : job_t;
+                               taskport        : task_t;
+out                            asport          : mach_port_t
+);
+
+routine
+info(
+                               j                       : job_t;
+out                            names           : name_array_t, dealloc;
+out                            jobs            : name_array_t, dealloc;
+out                            actives         : bootstrap_status_array_t, dealloc;
+                               flags           : uint64_t
+);
+
+routine
+subset(
+                               j                       : job_t;
+                               reqport         : mach_port_t;
+out                            subsetport      : mach_port_make_send_t
+);
+
+routine
+setup_shmem(
+                               j                       : job_t;
+out                            shmemport       : mach_port_move_send_t
+);
+
+routine
+take_subset(
+                               j                       : job_t;
+out                            reqport         : mach_port_move_send_t;
+out                            recvport        : mach_port_move_receive_t;
+out                            jobs            : pointer_t, dealloc;
+out                            ports           : mach_port_move_send_array_t, dealloc
+);
+
+routine
+getsocket(
+                               j                       : job_t;
+out                            sockpath        : name_t
+);
+
+skip; /* Formerly spawn. */
+
+skip; /* Formerly wait. */
+
+skip; /* Formerly uncork_fork. */
+
+routine
+swap_integer(
+                               j                       : job_t;
+                               inkey           : vproc_gsk_t;
+                               outkey          : vproc_gsk_t;
+                               inval           : int64_t;
+out                            outval          : int64_t
+);
+
+routine
+log(
+                               j                       : job_t;
+                               pri                     : integer_t;
+                               err                     : integer_t;
+                               message         : logmsg_t
+);
+
+routine
+lookup_per_user_context(
+                               j                       : job_t;
+                               uid                     : uid_t;
+out                            userbport       : mach_port_t
+);
+
+routine
+move_subset(
+                               j                       : job_t;
+                               targetport      : mach_port_t;
+                               session         : name_t;
+                               asport          : mach_port_t;
+                               flags           : uint64_t
+);
+
+routine
+swap_complex(
+                               j                       : job_t;
+                               inkey           : vproc_gsk_t;
+                               outkey          : vproc_gsk_t;
+                               inval           : pointer_t;
+out                            outval          : pointer_t, dealloc
+);
+
+routine
+log_drain(
+                               j                       : job_t;
+sreplyport             rp                      : mach_port_make_send_once_t;
+out                            outval          : pointer_t, dealloc
+);
+
+routine
+log_forward(
+                               j                       : job_t;
+                               inval           : pointer_t
+);
+
+routine
+kickstart(
+                               j                       : job_t;
+                               label           : name_t;
+out                            pid                     : pid_t;
+                               flags           : natural_t
+);
+
+skip;
+
+routine
+lookup_children(
+                               j                       : job_t;
+out                    childports      : mach_port_move_send_array_t, dealloc;
+out                            childnames      : name_array_t, dealloc;
+out                            childprops      : bootstrap_property_array_t, dealloc
+);
+
+routine
+switch_to_session(
+                               j                       : job_t;
+                               reqport         : mach_port_t;
+                               session         : name_t;
+                               asport          : mach_port_t;
+out                            newbsport       : mach_port_make_send_t
+);
+
+routine
+transaction_count_for_pid(
+                               j                       : job_t;
+                               pid                     : pid_t;
+out                            count           : integer_t;
+out                            condemned       : boolean_t
+);
                                
                                
-routine pid_is_managed(
-                               __bs_port                       : job_t;
-                               __pid                           : pid_t;
-out                            __managed                       : boolean_t);
-
-routine port_for_label(
-                               __bs_port                       : job_t;
-                               __label                         : name_t;
-out                            __mp                            : mach_port_make_send_t);
-
-routine init_session(
-                               __bs_port                       : job_t;
-                               __session_name          : name_t;
-                               __audit_session         : mach_port_t);
-
-routine set_security_session(
-                               __bs_port                       : job_t;
-                               __uuid                          : uuid_t;
-                               __session                       : mach_port_t);
-
-routine wait2(
-                               __bs_port                       : job_t;
-                               __target_port           : job_t;
-sreplyport             __rport                         : mach_port_make_send_once_t;
-out                            __waitval                       : integer_t;
-                               __legacy                        : boolean_t);
+routine
+pid_is_managed(
+                               j                       : job_t;
+                               pid                     : pid_t;
+out                            managed         : boolean_t
+);
+
+routine
+port_for_label(
+                               j                       : job_t;
+                               label           : name_t;
+out                            jport           : mach_port_make_send_t
+);
+
+routine
+init_session(
+                               j                       : job_t;
+                               session         : name_t;
+                               asport          : mach_port_t
+);
+
+routine
+set_security_session(
+                               j                       : job_t;
+                               uuid            : uuid_t;
+                               asport          : mach_port_t
+);
+
+skip; /* Formerly wait2. */
+
+routine
+event_source_check_in(
+                               j                       : job_t;
+                               stream          : name_t;
+                               pingport        : mach_port_make_send_once_t;
+out                            events          : pointer_t, dealloc;
+out                            tokens          : event_token_array_t
+);
+
+routine
+event_set_state(
+                               j                       : job_t;
+                               stream          : name_t;
+                               token           : uint64_t;
+                               state           : boolean_t
+);
+
+routine
+spawn2(
+                               j                       : job_t;
+sreplyport             rp                      : mach_port_make_send_once_t;
+                               job                     : pointer_t;
+                               asport          : mach_port_t;
+out                            outpid          : pid_t;
+out                            obsrvport       : mach_port_move_receive_t
+);
+
+routine
+get_root_bootstrap(
+                               j                       : job_t;
+out                            rootbs          : mach_port_move_send_t
+);
index 654ce4966a6c4c2a238f62a6021874453164b3be..0fe3a566fbfab1cac15345184952f9cb5bed96ac 100644 (file)
@@ -122,8 +122,8 @@ network_mount()
     case "${mount_from}" in
        afp:*)
                fstype=afp
     case "${mount_from}" in
        afp:*)
                fstype=afp
-               kextutil -v 0 /System/Library/Filesystems/AppleShare/asp_tcp.kext
-               kextutil -v 0 /System/Library/Filesystems/AppleShare/afpfs.kext
+               kextload -v 0 /System/Library/Filesystems/AppleShare/asp_tcp.kext
+               kextload -v 0 /System/Library/Filesystems/AppleShare/afpfs.kext
                ;;
        nfs:*) fstype=nfs;;
        *) echo "unknown network filesystem mount from ${mount_from}"
                ;;
        nfs:*) fstype=nfs;;
        *) echo "unknown network filesystem mount from ${mount_from}"
index be397b8922f8ca6c8d091dc6320db040e705f7ef..ac5a67fcd98875b363c159252d402336e736fcd9 100644 (file)
@@ -97,7 +97,7 @@ typedef struct vproc_transaction_s *vproc_transaction_t;
  * Call this API before creating data that needs to be saved via I/O later.
  */
 vproc_transaction_t
  * Call this API before creating data that needs to be saved via I/O later.
  */
 vproc_transaction_t
-vproc_transaction_begin(vproc_t virtual_proc) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
+vproc_transaction_begin(vproc_t virtual_proc) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0);
 
 /*!
  * @function vproc_transaction_end
 
 /*!
  * @function vproc_transaction_end
@@ -115,7 +115,7 @@ vproc_transaction_begin(vproc_t virtual_proc) __OSX_AVAILABLE_STARTING(__MAC_10_
  * Calling this API with the same handle more than once is undefined.
  */
 void
  * Calling this API with the same handle more than once is undefined.
  */
 void
-vproc_transaction_end(vproc_t virtual_proc, vproc_transaction_t handle) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
+vproc_transaction_end(vproc_t virtual_proc, vproc_transaction_t handle) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0);
 
 /*!
  * @typedef    vproc_standby_t
 
 /*!
  * @typedef    vproc_standby_t
index 2012b6f0df1c922ee238e33e8ce6b3383bd22e2c..b295aaf7ef8f3004df25d8e99b66e0f468504248 100644 (file)
 #include <sys/syscall.h>
 #include <bsm/audit.h>
 #include "launch.h"
 #include <sys/syscall.h>
 #include <bsm/audit.h>
 #include "launch.h"
-#include "bootstrap.h"
+#include "bootstrap_priv.h"
 #include "vproc.h"
 
 typedef char * _internal_string_t;
 typedef char * logmsg_t;
 typedef pid_t * pid_array_t;
 typedef mach_port_t vproc_mig_t;
 #include "vproc.h"
 
 typedef char * _internal_string_t;
 typedef char * logmsg_t;
 typedef pid_t * pid_array_t;
 typedef mach_port_t vproc_mig_t;
+typedef uint64_t event_token_array_t[1024];
 
 #define VPROC_SHMEM_EXITING    0x1
 
 
 #define VPROC_SHMEM_EXITING    0x1
 
@@ -44,7 +45,7 @@ struct vproc_shmem_s {
        int32_t vp_shmem_flags;
 };
 
        int32_t vp_shmem_flags;
 };
 
-#ifdef protocol_vproc_MSG_COUNT
+#if defined(protocol_vproc_MSG_COUNT) || defined (xpc_domain_MSG_COUNT) || defined (xpc_events_MSG_COUNT)
 /* HACK */
 #include "launchd_core_logic.h"
 #endif
 /* HACK */
 #include "launchd_core_logic.h"
 #endif
index b691c22ef10b81e472487d60a9ebf0bae0734aea..889362870d46bf34258f63ae711b351b7f4feca4 100644 (file)
@@ -29,6 +29,7 @@
 #include <launch.h>
 #include <vproc.h>
 #include <uuid/uuid.h>
 #include <launch.h>
 #include <vproc.h>
 #include <uuid/uuid.h>
+#include <servers/bootstrap.h>
 
 #ifndef VPROC_HAS_TRANSACTIONS
        #define VPROC_HAS_TRANSACTIONS
 
 #ifndef VPROC_HAS_TRANSACTIONS
        #define VPROC_HAS_TRANSACTIONS
@@ -43,6 +44,8 @@ __BEGIN_DECLS
 /* DO NOT use this. This is a hack for 'loginwindow' */
 #define VPROC_MAGIC_TRYKILL_SIGNAL     0x6161706C
 
 /* DO NOT use this. This is a hack for 'loginwindow' */
 #define VPROC_MAGIC_TRYKILL_SIGNAL     0x6161706C
 
+typedef void (*_vproc_transaction_callout)(void);
+
 typedef enum {
        VPROC_GSK_LAST_EXIT_STATUS = 1,
        VPROC_GSK_GLOBAL_ON_DEMAND,
 typedef enum {
        VPROC_GSK_LAST_EXIT_STATUS = 1,
        VPROC_GSK_GLOBAL_ON_DEMAND,
@@ -72,6 +75,14 @@ typedef enum {
        VPROC_GSK_EMBEDDEDROOTEQUIVALENT,
 } vproc_gsk_t;
 
        VPROC_GSK_EMBEDDEDROOTEQUIVALENT,
 } vproc_gsk_t;
 
+typedef kern_return_t (*vproc_helper_recv_ping_t)(mach_port_t, audit_token_t);
+
+/* Give to dispatch_mig_server(). */
+boolean_t vprocmgr_helper_server_routine_for_dispatch(mach_msg_header_t *message, mach_msg_header_t *reply);
+
+/* Give to dispatch_mig_server(). */
+extern size_t vprocmgr_helper_maxmsgsz;
+
 typedef unsigned int vproc_flags_t;
 /* For _vproc_kickstart_by_label() -- instructs launchd to kickstart the job to stall before exec(2). */
 #define VPROCFLAG_STALL_JOB_EXEC       1 << 1
 typedef unsigned int vproc_flags_t;
 /* For _vproc_kickstart_by_label() -- instructs launchd to kickstart the job to stall before exec(2). */
 #define VPROCFLAG_STALL_JOB_EXEC       1 << 1
@@ -93,7 +104,6 @@ vproc_err_t _vprocmgr_log_drain(vproc_t vp, pthread_mutex_t *optional_mutex_arou
 
 vproc_err_t _vproc_send_signal_by_label(const char *label, int sig);
 vproc_err_t _vproc_kickstart_by_label(const char *label, pid_t *out_pid, mach_port_t *out_port_name, mach_port_t *out_obsrvr_port, vproc_flags_t flags);
 
 vproc_err_t _vproc_send_signal_by_label(const char *label, int sig);
 vproc_err_t _vproc_kickstart_by_label(const char *label, pid_t *out_pid, mach_port_t *out_port_name, mach_port_t *out_obsrvr_port, vproc_flags_t flags);
-vproc_err_t _vproc_wait_by_label(const char *label, int *out_wstatus);
 
 void _vproc_log(int pri, const char *msg, ...) __attribute__((format(printf, 2, 3)));
 void _vproc_log_error(int pri, const char *msg, ...) __attribute__((format(printf, 2, 3)));
 
 void _vproc_log(int pri, const char *msg, ...) __attribute__((format(printf, 2, 3)));
 void _vproc_log_error(int pri, const char *msg, ...) __attribute__((format(printf, 2, 3)));
@@ -105,21 +115,69 @@ void _vproc_logv(int pri, int err, const char *msg, va_list ap) __attribute__((f
 #define VPROCMGR_SESSION_STANDARDIO            "StandardIO"
 #define VPROCMGR_SESSION_SYSTEM                        "System"
 
 #define VPROCMGR_SESSION_STANDARDIO            "StandardIO"
 #define VPROCMGR_SESSION_SYSTEM                        "System"
 
+#define XPC_DOMAIN_TYPE_SYSTEM                 "XPCSystem"
+#define XPC_DOMAIN_TYPE_PERUSER                        "XPCPerUser"
+#define XPC_DOMAIN_TYPE_PERSESSION             "XPCPerSession"
+#define XPC_DOMAIN_TYPE_PERAPPLICATION "XPCPerApplication"
+
 vproc_err_t _vprocmgr_move_subset_to_user(uid_t target_user, const char *session_type, uint64_t flags);
 vproc_err_t _vprocmgr_switch_to_session(const char *target_session, vproc_flags_t flags);
 vproc_err_t _vprocmgr_detach_from_console(vproc_flags_t flags);
 
 vproc_err_t _vprocmgr_move_subset_to_user(uid_t target_user, const char *session_type, uint64_t flags);
 vproc_err_t _vprocmgr_switch_to_session(const char *target_session, vproc_flags_t flags);
 vproc_err_t _vprocmgr_detach_from_console(vproc_flags_t flags);
 
-void _vproc_standby_begin(void)                                                                                                                                __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
-void _vproc_standby_end(void)                                                                                                                          __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
-size_t _vproc_standby_count(void)                                                                                                                      __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
-size_t _vproc_standby_timeout(void)                                                                                                                    __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
-
-kern_return_t _vproc_transaction_count_for_pid(pid_t p, int32_t *count, bool *condemned)       __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
-bool _vproc_pid_is_managed(pid_t p)                                                                                                                    __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
-void _vproc_transaction_try_exit(int status)                                                                                           __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
-void _vproc_transaction_begin(void)                                                                                                                    __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
-void _vproc_transaction_end(void)                                                                                                                      __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
-size_t _vproc_transaction_count(void)                                                                                                          __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA);
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA)
+void
+_vproc_standby_begin(void);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA)
+void
+_vproc_standby_end(void);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA)
+size_t
+_vproc_standby_count(void);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA)
+size_t
+_vproc_standby_timeout(void);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA)
+kern_return_t
+_vproc_transaction_count_for_pid(pid_t p, int32_t *count, bool *condemned);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA)
+bool
+_vproc_pid_is_managed(pid_t p);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA)
+void
+_vproc_transaction_try_exit(int status);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0)
+void
+_vproc_transaction_begin(void);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0)
+void
+_vproc_transaction_end(void);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA)
+size_t
+_vproc_transaction_count(void);
+
+int32_t *
+_vproc_transaction_ptr(void);
+
+void
+_vproc_transaction_set_callouts(_vproc_transaction_callout gone2zero, _vproc_transaction_callout gonenonzero);
+
+bool
+vprocmgr_helper_check_in(const char *sysname, mach_port_t rp, launch_data_t *events, uint64_t *tokens);
+
+bool
+vprocmgr_helper_event_set_state(const char *sysname, uint64_t token, bool state);
+
+void
+vprocmgr_helper_register(vproc_helper_recv_ping_t callout);
 
 #pragma GCC visibility pop
 
 
 #pragma GCC visibility pop