objects = {
/* Begin PBXAggregateTarget section */
- 72B71BBA0EA8091300BFE986 /* embedded */ = {
+ 726056200EA8088C00D65FE7 /* embedded */ = {
isa = PBXAggregateTarget;
- buildConfigurationList = 72B71BC40EA8095200BFE986 /* Build configuration list for PBXAggregateTarget "embedded" */;
+ buildConfigurationList = 7260562B0EA808D800D65FE7 /* Build configuration list for PBXAggregateTarget "embedded" */;
buildPhases = (
);
dependencies = (
- 72B71BBD0EA8092300BFE986 /* PBXTargetDependency */,
- 72B71BBF0EA8092500BFE986 /* PBXTargetDependency */,
- 72B71BC10EA8092700BFE986 /* PBXTargetDependency */,
- 72B71BC30EA8092F00BFE986 /* PBXTargetDependency */,
+ 4B10F1E20F43BEA900875782 /* PBXTargetDependency */,
+ 4B10F1F60F43BF8C00875782 /* PBXTargetDependency */,
+ 726056270EA808B700D65FE7 /* PBXTargetDependency */,
+ 726056290EA808B900D65FE7 /* PBXTargetDependency */,
);
name = embedded;
productName = embedded;
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
- 33C2D68C0F8F2C7A00A21214 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 721FBEBB0EA7AE2F0057462B /* Security.framework */; };
+ 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 */; };
+ 4B10F1BC0F43BE7E00875782 /* mach_exc.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC36291F0E9349410054F1A3 /* mach_exc.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ 4B10F1BD0F43BE7E00875782 /* notify.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC36290C0E93475F0054F1A3 /* notify.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ 4B10F1BE0F43BE7E00875782 /* launchd.c in Sources */ = {isa = PBXBuildFile; fileRef = FC59A0C40E8C8A4700D41150 /* launchd.c */; };
+ 4B10F1BF0F43BE7E00875782 /* launchd_runtime.c in Sources */ = {isa = PBXBuildFile; fileRef = FC59A0B50E8C8A1F00D41150 /* launchd_runtime.c */; settings = {COMPILER_FLAGS = "-I\"$SYMROOT\""; }; };
+ 4B10F1C00F43BE7E00875782 /* launchd_runtime_kill.c in Sources */ = {isa = PBXBuildFile; fileRef = FC59A0B30E8C8A1F00D41150 /* launchd_runtime_kill.c */; };
+ 4B10F1C10F43BE7E00875782 /* launchd_core_logic.c in Sources */ = {isa = PBXBuildFile; fileRef = FC59A0B70E8C8A1F00D41150 /* launchd_core_logic.c */; };
+ 4B10F1C20F43BE7E00875782 /* launchd_unix_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = FC59A0B10E8C8A1F00D41150 /* launchd_unix_ipc.c */; };
+ 4B10F1C30F43BE7E00875782 /* launchd_ktrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 72FDB15D0EA7D7B200B2AC84 /* launchd_ktrace.c */; };
+ 4B10F1C40F43BE7E00875782 /* protocol_job_forward.defs in Sources */ = {isa = PBXBuildFile; fileRef = 72FDB1BF0EA7E21C00B2AC84 /* protocol_job_forward.defs */; };
+ 4B10F1C60F43BE7E00875782 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FC36292C0E934AA40054F1A3 /* libbsm.dylib */; };
+ 4B10F1C90F43BE7E00875782 /* launchd.conf.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC59A0C30E8C8A4700D41150 /* launchd.conf.5 */; };
+ 4B10F1CA0F43BE7E00875782 /* launchd.plist.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC59A0C10E8C8A4700D41150 /* launchd.plist.5 */; };
+ 4B10F1CC0F43BE7E00875782 /* launchd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC59A0C00E8C8A3A00D41150 /* launchd.8 */; };
+ 4B10F1CD0F43BE7E00875782 /* rc.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC59A0F80E8C8AC300D41150 /* rc.8 */; };
+ 4B10F1CF0F43BE7E00875782 /* rc.netboot in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC59A0F90E8C8AC300D41150 /* rc.netboot */; };
+ 4B10F1E80F43BF5C00875782 /* launchctl.c in Sources */ = {isa = PBXBuildFile; fileRef = FC59A0AE0E8C8A0E00D41150 /* launchctl.c */; settings = {COMPILER_FLAGS = "-I\"$SDKROOT\"/System/Library/Frameworks/System.framework/PrivateHeaders"; }; };
+ 4B10F1EA0F43BF5C00875782 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC36283E0E93463C0054F1A3 /* IOKit.framework */; };
+ 4B10F1EB0F43BF5C00875782 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC3628070E9345E10054F1A3 /* CoreFoundation.framework */; };
+ 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 */; };
+ 4B9EDCA20EAFC77E00A78496 /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */; };
+ 7215DE4C0EFAF2EC00ABD81E /* libauditd.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */; };
721FBEBC0EA7AE2F0057462B /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 721FBEBB0EA7AE2F0057462B /* Security.framework */; };
- 72B71B7D0EA7E98A00BFE986 /* exc.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC36291F0E9349410054F1A3 /* exc.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ 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 */; };
+ 72FDB15F0EA7D7B200B2AC84 /* launchd_ktrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 72FDB15D0EA7D7B200B2AC84 /* launchd_ktrace.c */; };
+ 72FDB1C00EA7E21C00B2AC84 /* protocol_job_forward.defs in Sources */ = {isa = PBXBuildFile; fileRef = 72FDB1BF0EA7E21C00B2AC84 /* protocol_job_forward.defs */; };
FC3627BA0E9343220054F1A3 /* StartupItems.c in Sources */ = {isa = PBXBuildFile; fileRef = FC59A0FD0E8C8ADF00D41150 /* StartupItems.c */; };
FC3627BB0E93432A0054F1A3 /* SystemStarter.c in Sources */ = {isa = PBXBuildFile; fileRef = FC59A1000E8C8ADF00D41150 /* SystemStarter.c */; };
FC3627D40E93439B0054F1A3 /* StartupItemContext.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC59A0FE0E8C8ADF00D41150 /* StartupItemContext.8 */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
- 72B71BBC0EA8092300BFE986 /* PBXContainerItemProxy */ = {
+ 4B10F1E10F43BEA900875782 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = FC59A03F0E8C87FD00D41150 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = FC59A0530E8C884700D41150;
- remoteInfo = launchd;
+ remoteGlobalIDString = 4B10F1B70F43BE7E00875782;
+ remoteInfo = "launchd-embedded";
};
- 72B71BBE0EA8092500BFE986 /* PBXContainerItemProxy */ = {
+ 4B10F1F50F43BF8C00875782 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = FC59A03F0E8C87FD00D41150 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = FC59A06C0E8C888A00D41150;
- remoteInfo = launchctl;
+ remoteGlobalIDString = 4B10F1E60F43BF5C00875782;
+ remoteInfo = "launchctl-embedded";
};
- 72B71BC00EA8092700BFE986 /* PBXContainerItemProxy */ = {
+ 726056260EA808B700D65FE7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = FC59A03F0E8C87FD00D41150 /* Project object */;
proxyType = 1;
remoteGlobalIDString = FC59A0CD0E8C8A5C00D41150;
remoteInfo = launchproxy;
};
- 72B71BC20EA8092F00BFE986 /* PBXContainerItemProxy */ = {
+ 726056280EA808B900D65FE7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = FC59A03F0E8C87FD00D41150 /* Project object */;
proxyType = 1;
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
+ 4B10F1C80F43BE7E00875782 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ 4B10F1C90F43BE7E00875782 /* launchd.conf.5 in CopyFiles */,
+ 4B10F1CA0F43BE7E00875782 /* launchd.plist.5 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4B10F1CB0F43BE7E00875782 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 4B10F1CC0F43BE7E00875782 /* launchd.8 in CopyFiles */,
+ 4B10F1CD0F43BE7E00875782 /* rc.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4B10F1CE0F43BE7E00875782 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = private/etc;
+ dstSubfolderSpec = 0;
+ files = (
+ 4B10F1CF0F43BE7E00875782 /* rc.netboot in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4B10F1EE0F43BF5C00875782 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 4B10F1EF0F43BF5C00875782 /* launchctl.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4B1D91F40F8BDE6800125940 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = usr/local/share/sandbox/operations/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4B1D92010F8BDE7D00125940 /* launchd.ops in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
FC3627D60E9343B90054F1A3 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 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>"; };
+ 4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = /System/Library/Frameworks/DiskArbitration.framework; sourceTree = "<absolute>"; };
+ 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>"; };
FC36290C0E93475F0054F1A3 /* notify.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = notify.defs; path = /usr/include/mach/notify.defs; sourceTree = "<absolute>"; };
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 /* exc.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = exc.defs; path = /usr/include/mach/exc.defs; sourceTree = "<absolute>"; };
+ FC36291F0E9349410054F1A3 /* mach_exc.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = mach_exc.defs; path = /usr/include/mach/mach_exc.defs; sourceTree = "<absolute>"; };
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; };
FC59A0A50E8C89C100D41150 /* IPC.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = IPC.c; path = launchd/src/IPC.c; sourceTree = SOURCE_ROOT; };
FC59A0AD0E8C8A0E00D41150 /* launchctl.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = launchctl.1; path = launchd/src/launchctl.1; sourceTree = SOURCE_ROOT; };
FC59A0AE0E8C8A0E00D41150 /* launchctl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchctl.c; path = launchd/src/launchctl.c; sourceTree = SOURCE_ROOT; };
- FC59A0B00E8C8A1F00D41150 /* launchd_unix_ipc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd_unix_ipc.h; path = launchd/src/launchd_unix_ipc.h; sourceTree = SOURCE_ROOT; };
- FC59A0B10E8C8A1F00D41150 /* launchd_unix_ipc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd_unix_ipc.c; path = launchd/src/launchd_unix_ipc.c; sourceTree = SOURCE_ROOT; };
- FC59A0B20E8C8A1F00D41150 /* launchd_runtime_kill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd_runtime_kill.h; path = launchd/src/launchd_runtime_kill.h; sourceTree = SOURCE_ROOT; };
- FC59A0B30E8C8A1F00D41150 /* launchd_runtime_kill.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd_runtime_kill.c; path = launchd/src/launchd_runtime_kill.c; sourceTree = SOURCE_ROOT; };
- FC59A0B40E8C8A1F00D41150 /* launchd_runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd_runtime.h; path = launchd/src/launchd_runtime.h; sourceTree = SOURCE_ROOT; };
- FC59A0B50E8C8A1F00D41150 /* launchd_runtime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd_runtime.c; path = launchd/src/launchd_runtime.c; sourceTree = SOURCE_ROOT; };
- FC59A0B60E8C8A1F00D41150 /* launchd_core_logic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd_core_logic.h; path = launchd/src/launchd_core_logic.h; sourceTree = SOURCE_ROOT; };
- FC59A0B70E8C8A1F00D41150 /* launchd_core_logic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd_core_logic.c; path = launchd/src/launchd_core_logic.c; sourceTree = SOURCE_ROOT; };
- FC59A0BC0E8C8A2A00D41150 /* launchd_mig_types.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = launchd_mig_types.defs; path = launchd/src/launchd_mig_types.defs; sourceTree = SOURCE_ROOT; };
- FC59A0BD0E8C8A2A00D41150 /* launchd_internal.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = launchd_internal.defs; path = launchd/src/launchd_internal.defs; sourceTree = SOURCE_ROOT; };
- FC59A0C00E8C8A3A00D41150 /* launchd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = launchd.8; path = launchd/src/launchd.8; sourceTree = SOURCE_ROOT; };
- FC59A0C10E8C8A4700D41150 /* launchd.plist.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = launchd.plist.5; path = launchd/src/launchd.plist.5; sourceTree = SOURCE_ROOT; };
- FC59A0C20E8C8A4700D41150 /* launchd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd.h; path = launchd/src/launchd.h; sourceTree = SOURCE_ROOT; };
- FC59A0C30E8C8A4700D41150 /* launchd.conf.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = launchd.conf.5; path = launchd/src/launchd.conf.5; sourceTree = SOURCE_ROOT; };
- FC59A0C40E8C8A4700D41150 /* launchd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd.c; path = launchd/src/launchd.c; sourceTree = SOURCE_ROOT; };
+ FC59A0B00E8C8A1F00D41150 /* launchd_unix_ipc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd_unix_ipc.h; path = launchd/src/launchd_unix_ipc.h; sourceTree = "<group>"; };
+ FC59A0B10E8C8A1F00D41150 /* launchd_unix_ipc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd_unix_ipc.c; path = launchd/src/launchd_unix_ipc.c; sourceTree = "<group>"; };
+ FC59A0B20E8C8A1F00D41150 /* launchd_runtime_kill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd_runtime_kill.h; path = launchd/src/launchd_runtime_kill.h; sourceTree = "<group>"; };
+ FC59A0B30E8C8A1F00D41150 /* launchd_runtime_kill.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd_runtime_kill.c; path = launchd/src/launchd_runtime_kill.c; sourceTree = "<group>"; };
+ FC59A0B40E8C8A1F00D41150 /* launchd_runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd_runtime.h; path = launchd/src/launchd_runtime.h; sourceTree = "<group>"; };
+ FC59A0B50E8C8A1F00D41150 /* launchd_runtime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd_runtime.c; path = launchd/src/launchd_runtime.c; sourceTree = "<group>"; };
+ FC59A0B60E8C8A1F00D41150 /* launchd_core_logic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd_core_logic.h; path = launchd/src/launchd_core_logic.h; sourceTree = "<group>"; };
+ FC59A0B70E8C8A1F00D41150 /* launchd_core_logic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd_core_logic.c; path = launchd/src/launchd_core_logic.c; sourceTree = "<group>"; };
+ FC59A0BC0E8C8A2A00D41150 /* launchd_mig_types.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = launchd_mig_types.defs; path = launchd/src/launchd_mig_types.defs; sourceTree = "<group>"; };
+ FC59A0BD0E8C8A2A00D41150 /* launchd_internal.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = launchd_internal.defs; path = launchd/src/launchd_internal.defs; sourceTree = "<group>"; };
+ FC59A0C00E8C8A3A00D41150 /* launchd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = launchd.8; path = launchd/src/launchd.8; sourceTree = "<group>"; };
+ FC59A0C10E8C8A4700D41150 /* launchd.plist.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = launchd.plist.5; path = launchd/src/launchd.plist.5; sourceTree = "<group>"; };
+ FC59A0C20E8C8A4700D41150 /* launchd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launchd.h; path = launchd/src/launchd.h; sourceTree = "<group>"; };
+ FC59A0C30E8C8A4700D41150 /* launchd.conf.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = launchd.conf.5; path = launchd/src/launchd.conf.5; sourceTree = "<group>"; };
+ FC59A0C40E8C8A4700D41150 /* launchd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchd.c; path = launchd/src/launchd.c; sourceTree = "<group>"; };
FC59A0CE0E8C8A5C00D41150 /* launchproxy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = launchproxy; sourceTree = BUILT_PRODUCTS_DIR; };
FC59A0DA0E8C8A6900D41150 /* launchproxy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = launchproxy.c; path = launchd/src/launchproxy.c; sourceTree = SOURCE_ROOT; };
FC59A0DB0E8C8A6900D41150 /* launchproxy.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = launchproxy.8; path = launchd/src/launchproxy.8; sourceTree = SOURCE_ROOT; };
FC59A0EA0E8C8AA600D41150 /* bootstrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bootstrap.h; path = launchd/src/bootstrap.h; sourceTree = "<group>"; };
FC59A0EB0E8C8AA600D41150 /* bootstrap_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bootstrap_priv.h; path = launchd/src/bootstrap_priv.h; sourceTree = "<group>"; };
FC59A0EC0E8C8AA600D41150 /* libbootstrap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = libbootstrap.c; path = launchd/src/libbootstrap.c; sourceTree = SOURCE_ROOT; };
- FC59A0F80E8C8AC300D41150 /* rc.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = rc.8; path = launchd/src/rc.8; sourceTree = SOURCE_ROOT; };
- FC59A0F90E8C8AC300D41150 /* rc.netboot */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = rc.netboot; path = launchd/src/rc.netboot; sourceTree = SOURCE_ROOT; };
- FC59A0FA0E8C8AC300D41150 /* rc.common */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = rc.common; path = launchd/src/rc.common; sourceTree = SOURCE_ROOT; };
+ FC59A0F80E8C8AC300D41150 /* rc.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = rc.8; path = launchd/src/rc.8; sourceTree = "<group>"; };
+ FC59A0F90E8C8AC300D41150 /* rc.netboot */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = rc.netboot; path = launchd/src/rc.netboot; sourceTree = "<group>"; };
+ FC59A0FA0E8C8AC300D41150 /* rc.common */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = rc.common; path = launchd/src/rc.common; sourceTree = "<group>"; };
FC59A0FB0E8C8ACE00D41150 /* reboot2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = reboot2.h; path = launchd/src/reboot2.h; sourceTree = SOURCE_ROOT; };
FC59A0FD0E8C8ADF00D41150 /* StartupItems.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = StartupItems.c; path = launchd/src/StartupItems.c; sourceTree = SOURCE_ROOT; };
FC59A0FE0E8C8ADF00D41150 /* StartupItemContext.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = StartupItemContext.8; path = launchd/src/StartupItemContext.8; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
+ 4B10F1C50F43BE7E00875782 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4B10F1C60F43BE7E00875782 /* libbsm.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4B10F1E90F43BF5C00875782 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4B10F1EA0F43BF5C00875782 /* IOKit.framework in Frameworks */,
+ 4B10F1EB0F43BF5C00875782 /* CoreFoundation.framework in Frameworks */,
+ 4B10F1EC0F43BF5C00875782 /* libedit.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
FC59A0520E8C884700D41150 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
FC36292D0E934AA40054F1A3 /* libbsm.dylib in Frameworks */,
+ 7215DE4C0EFAF2EC00ABD81E /* libauditd.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
FCC841CC0EA7138700C01666 /* IOKit.framework in Frameworks */,
FC3628080E9345E10054F1A3 /* CoreFoundation.framework in Frameworks */,
FCD713740E95DE49001B0111 /* libedit.dylib in Frameworks */,
- 33C2D68C0F8F2C7A00A21214 /* Security.framework in Frameworks */,
+ 72AFE8090EFAF3D9004BDA46 /* libauditd.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
files = (
FC3628090E9345E10054F1A3 /* CoreFoundation.framework in Frameworks */,
FC36283F0E93463C0054F1A3 /* IOKit.framework in Frameworks */,
+ 4B9EDCA20EAFC77E00A78496 /* DiskArbitration.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 4B9EDCD60EAFD11000A78496 /* MIG */ = {
+ isa = PBXGroup;
+ children = (
+ FC59A0BC0E8C8A2A00D41150 /* launchd_mig_types.defs */,
+ 72FDB1BF0EA7E21C00B2AC84 /* protocol_job_forward.defs */,
+ FC3629160E9348390054F1A3 /* protocol_job_reply.defs */,
+ FC3627DF0E9344BF0054F1A3 /* protocol_vproc.defs */,
+ FC59A0BD0E8C8A2A00D41150 /* launchd_internal.defs */,
+ FC36291F0E9349410054F1A3 /* mach_exc.defs */,
+ FC36290C0E93475F0054F1A3 /* notify.defs */,
+ );
+ name = MIG;
+ sourceTree = "<group>";
+ };
+ 4B9EDCD70EAFD14500A78496 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 721FBEA50EA7ABC40057462B /* config.h */,
+ FC59A0C20E8C8A4700D41150 /* launchd.h */,
+ FC59A0C40E8C8A4700D41150 /* launchd.c */,
+ FC59A0B00E8C8A1F00D41150 /* launchd_unix_ipc.h */,
+ FC59A0B10E8C8A1F00D41150 /* launchd_unix_ipc.c */,
+ FC59A0B20E8C8A1F00D41150 /* launchd_runtime_kill.h */,
+ FC59A0B30E8C8A1F00D41150 /* launchd_runtime_kill.c */,
+ FC59A0B40E8C8A1F00D41150 /* launchd_runtime.h */,
+ FC59A0B50E8C8A1F00D41150 /* launchd_runtime.c */,
+ FC59A0B60E8C8A1F00D41150 /* launchd_core_logic.h */,
+ FC59A0B70E8C8A1F00D41150 /* launchd_core_logic.c */,
+ 72FDB15E0EA7D7B200B2AC84 /* launchd_ktrace.h */,
+ 72FDB15D0EA7D7B200B2AC84 /* launchd_ktrace.c */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 4B9EDCD80EAFD15D00A78496 /* Documentation */ = {
+ isa = PBXGroup;
+ children = (
+ FC59A0F80E8C8AC300D41150 /* rc.8 */,
+ FC59A0C10E8C8A4700D41150 /* launchd.plist.5 */,
+ FC59A0C30E8C8A4700D41150 /* launchd.conf.5 */,
+ FC59A0C00E8C8A3A00D41150 /* launchd.8 */,
+ );
+ name = Documentation;
+ sourceTree = "<group>";
+ };
+ 4B9EDCD90EAFD19800A78496 /* rc */ = {
+ isa = PBXGroup;
+ children = (
+ FC59A0F90E8C8AC300D41150 /* rc.netboot */,
+ FC59A0FA0E8C8AC300D41150 /* rc.common */,
+ );
+ name = rc;
+ sourceTree = "<group>";
+ };
FC36280C0E9345F60054F1A3 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */,
721FBEBB0EA7AE2F0057462B /* Security.framework */,
FC36292C0E934AA40054F1A3 /* libbsm.dylib */,
+ 7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */,
FCD713730E95DE49001B0111 /* libedit.dylib */,
FC3628070E9345E10054F1A3 /* CoreFoundation.framework */,
FC36283E0E93463C0054F1A3 /* IOKit.framework */,
FC59A04E0E8C883300D41150 /* launchd */ = {
isa = PBXGroup;
children = (
- 721FBEA50EA7ABC40057462B /* config.h */,
- FC36291F0E9349410054F1A3 /* exc.defs */,
- FC3629160E9348390054F1A3 /* protocol_job_reply.defs */,
- FC36290C0E93475F0054F1A3 /* notify.defs */,
- FC59A0F80E8C8AC300D41150 /* rc.8 */,
- FC59A0F90E8C8AC300D41150 /* rc.netboot */,
- FC59A0FA0E8C8AC300D41150 /* rc.common */,
- FC59A0C10E8C8A4700D41150 /* launchd.plist.5 */,
- FC59A0C20E8C8A4700D41150 /* launchd.h */,
- FC59A0C30E8C8A4700D41150 /* launchd.conf.5 */,
- FC59A0C40E8C8A4700D41150 /* launchd.c */,
- FC59A0C00E8C8A3A00D41150 /* launchd.8 */,
- FC59A0BC0E8C8A2A00D41150 /* launchd_mig_types.defs */,
- FC59A0BD0E8C8A2A00D41150 /* launchd_internal.defs */,
- FC59A0B00E8C8A1F00D41150 /* launchd_unix_ipc.h */,
- FC59A0B10E8C8A1F00D41150 /* launchd_unix_ipc.c */,
- FC59A0B20E8C8A1F00D41150 /* launchd_runtime_kill.h */,
- FC59A0B30E8C8A1F00D41150 /* launchd_runtime_kill.c */,
- FC59A0B40E8C8A1F00D41150 /* launchd_runtime.h */,
- FC59A0B50E8C8A1F00D41150 /* launchd_runtime.c */,
- FC59A0B60E8C8A1F00D41150 /* launchd_core_logic.h */,
- FC59A0B70E8C8A1F00D41150 /* launchd_core_logic.c */,
+ 4B9EDCD60EAFD11000A78496 /* MIG */,
+ 4B9EDCD70EAFD14500A78496 /* Source */,
+ 4B9EDCD90EAFD19800A78496 /* rc */,
+ 4B9EDCD80EAFD15D00A78496 /* Documentation */,
);
name = launchd;
sourceTree = "<group>";
FC59A0910E8C892300D41150 /* SystemStarter */,
FC59A0CE0E8C8A5C00D41150 /* launchproxy */,
FCD7132B0E95D64D001B0111 /* wait4path */,
+ 4B10F1D30F43BE7E00875782 /* launchd */,
+ 4B10F1F30F43BF5C00875782 /* launchctl */,
);
name = Products;
sourceTree = "<group>";
FC59A0C80E8C8A4E00D41150 /* launchproxy */ = {
isa = PBXGroup;
children = (
- FC59A0DA0E8C8A6900D41150 /* launchproxy.c */,
FC59A0DB0E8C8A6900D41150 /* launchproxy.8 */,
+ FC59A0DA0E8C8A6900D41150 /* launchproxy.c */,
);
name = launchproxy;
sourceTree = "<group>";
FC59A0E10E8C8A9400D41150 /* liblaunch */ = {
isa = PBXGroup;
children = (
+ 4B1D91ED0F8BDE1A00125940 /* launchd.ops */,
FC59A0FB0E8C8ACE00D41150 /* reboot2.h */,
- FC3627DF0E9344BF0054F1A3 /* protocol_vproc.defs */,
FC59A0E20E8C8AA600D41150 /* vproc.h */,
FC59A0E30E8C8AA600D41150 /* vproc_priv.h */,
FC59A0E40E8C8AA600D41150 /* vproc_internal.h */,
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
+ 4B10F1B70F43BE7E00875782 /* launchd-embedded */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4B10F1D10F43BE7E00875782 /* Build configuration list for PBXNativeTarget "launchd-embedded" */;
+ buildPhases = (
+ 4B10F1B80F43BE7E00875782 /* Sources */,
+ 4B10F1C50F43BE7E00875782 /* Frameworks */,
+ 4B10F1C80F43BE7E00875782 /* CopyFiles */,
+ 4B10F1CB0F43BE7E00875782 /* CopyFiles */,
+ 4B10F1CE0F43BE7E00875782 /* CopyFiles */,
+ 4B10F1D00F43BE7E00875782 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "launchd-embedded";
+ productName = launchd;
+ productReference = 4B10F1D30F43BE7E00875782 /* launchd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4B10F1E60F43BF5C00875782 /* launchctl-embedded */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4B10F1F10F43BF5C00875782 /* Build configuration list for PBXNativeTarget "launchctl-embedded" */;
+ buildPhases = (
+ 4B10F1E70F43BF5C00875782 /* Sources */,
+ 4B10F1E90F43BF5C00875782 /* Frameworks */,
+ 4B10F1EE0F43BF5C00875782 /* CopyFiles */,
+ 4B10F1F00F43BF5C00875782 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "launchctl-embedded";
+ productName = launchctl;
+ productReference = 4B10F1F30F43BF5C00875782 /* launchctl */;
+ productType = "com.apple.product-type.tool";
+ };
FC59A0530E8C884700D41150 /* launchd */ = {
isa = PBXNativeTarget;
buildConfigurationList = FC59A0590E8C884800D41150 /* Build configuration list for PBXNativeTarget "launchd" */;
isa = PBXNativeTarget;
buildConfigurationList = FC59A0650E8C886700D41150 /* Build configuration list for PBXNativeTarget "liblaunch" */;
buildPhases = (
+ 4B1D91F40F8BDE6800125940 /* CopyFiles */,
FC59A05C0E8C885100D41150 /* Headers */,
FC59A05D0E8C885100D41150 /* Sources */,
FC59A05E0E8C885100D41150 /* Frameworks */,
projectRoot = "";
targets = (
FC59A0750E8C88AC00D41150 /* default */,
- 72B71BBA0EA8091300BFE986 /* embedded */,
+ 726056200EA8088C00D65FE7 /* embedded */,
FC59A07A0E8C88BB00D41150 /* launchd_libs */,
FC59A0530E8C884700D41150 /* launchd */,
FC59A06C0E8C888A00D41150 /* launchctl */,
+ 4B10F1B70F43BE7E00875782 /* launchd-embedded */,
+ 4B10F1E60F43BF5C00875782 /* launchctl-embedded */,
FC59A0CD0E8C8A5C00D41150 /* launchproxy */,
FCD7132A0E95D64D001B0111 /* wait4path */,
FC59A0900E8C892300D41150 /* SystemStarter */,
/* End PBXProject section */
/* Begin PBXShellScriptBuildPhase section */
+ 4B10F1D00F43BE7E00875782 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/Developer/Makefiles/bin/compress-man-pages.pl -d \"$DSTROOT\" /usr/share/man\n/bin/mkdir -p \"$DSTROOT/private/var/db/launchd.db/com.apple.launchd\"\n/usr/sbin/chown root:wheel \"$DSTROOT/private/var/db/launchd.db\"\n/usr/sbin/chown root:wheel \"$DSTROOT/private/var/db/launchd.db/com.apple.launchd\"\n\n";
+ showEnvVarsInLog = 0;
+ };
+ 4B10F1F00F43BF5C00875782 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "install -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/System/Library/LaunchAgents\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/System/Library/LaunchDaemons\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/Library/LaunchAgents\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/Library/LaunchDaemons\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/private/etc/mach_init.d\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/private/etc/mach_init_per_login_session.d\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/private/etc/mach_init_per_user.d\n/Developer/Makefiles/bin/compress-man-pages.pl -d \"$DSTROOT\" /usr/share/man";
+ showEnvVarsInLog = 0;
+ };
FC7B87B20EA7195F00542082 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = "/Developer/Makefiles/bin/compress-man-pages.pl -d \"$DSTROOT\" /usr/share/man";
+ shellScript = "/Developer/Makefiles/bin/compress-man-pages.pl -d \"$DSTROOT\" /usr/share/man\n/bin/mkdir -p \"$DSTROOT/private/var/db/launchd.db/com.apple.launchd\"\n/usr/sbin/chown root:wheel \"$DSTROOT/private/var/db/launchd.db\"\n/usr/sbin/chown root:wheel \"$DSTROOT/private/var/db/launchd.db/com.apple.launchd\"\n";
showEnvVarsInLog = 0;
};
FC7B87EE0EA71A4900542082 /* ShellScript */ = {
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ 4B10F1B80F43BE7E00875782 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4B10F1B90F43BE7E00875782 /* launchd_internal.defs in Sources */,
+ 4B10F1BA0F43BE7E00875782 /* protocol_vproc.defs in Sources */,
+ 4B10F1BB0F43BE7E00875782 /* protocol_job_reply.defs in Sources */,
+ 4B10F1BC0F43BE7E00875782 /* mach_exc.defs in Sources */,
+ 4B10F1BD0F43BE7E00875782 /* notify.defs in Sources */,
+ 4B10F1BE0F43BE7E00875782 /* launchd.c in Sources */,
+ 4B10F1BF0F43BE7E00875782 /* launchd_runtime.c in Sources */,
+ 4B10F1C00F43BE7E00875782 /* launchd_runtime_kill.c in Sources */,
+ 4B10F1C10F43BE7E00875782 /* launchd_core_logic.c in Sources */,
+ 4B10F1C20F43BE7E00875782 /* launchd_unix_ipc.c in Sources */,
+ 4B10F1C30F43BE7E00875782 /* launchd_ktrace.c in Sources */,
+ 4B10F1C40F43BE7E00875782 /* protocol_job_forward.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4B10F1E70F43BF5C00875782 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4B10F1E80F43BF5C00875782 /* launchctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
FC59A0510E8C884700D41150 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
FC59A0BF0E8C8A2A00D41150 /* launchd_internal.defs in Sources */,
FC3627E10E9344BF0054F1A3 /* protocol_vproc.defs in Sources */,
FC3629170E9348390054F1A3 /* protocol_job_reply.defs in Sources */,
- 72B71B7D0EA7E98A00BFE986 /* exc.defs in Sources */,
+ 726055EC0EA7EC2400D65FE7 /* mach_exc.defs in Sources */,
FC36290D0E93475F0054F1A3 /* notify.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 */,
+ 72FDB1C00EA7E21C00B2AC84 /* protocol_job_forward.defs in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
FC59A0F00E8C8AA600D41150 /* libvproc.c in Sources */,
FC59A0F70E8C8AA600D41150 /* libbootstrap.c in Sources */,
FC3627E00E9344BF0054F1A3 /* protocol_vproc.defs in Sources */,
+ 726056090EA7FCF200D65FE7 /* launchd_ktrace.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
- 72B71BBD0EA8092300BFE986 /* PBXTargetDependency */ = {
+ 4B10F1E20F43BEA900875782 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = FC59A0530E8C884700D41150 /* launchd */;
- targetProxy = 72B71BBC0EA8092300BFE986 /* PBXContainerItemProxy */;
+ target = 4B10F1B70F43BE7E00875782 /* launchd-embedded */;
+ targetProxy = 4B10F1E10F43BEA900875782 /* PBXContainerItemProxy */;
};
- 72B71BBF0EA8092500BFE986 /* PBXTargetDependency */ = {
+ 4B10F1F60F43BF8C00875782 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = FC59A06C0E8C888A00D41150 /* launchctl */;
- targetProxy = 72B71BBE0EA8092500BFE986 /* PBXContainerItemProxy */;
+ target = 4B10F1E60F43BF5C00875782 /* launchctl-embedded */;
+ targetProxy = 4B10F1F50F43BF8C00875782 /* PBXContainerItemProxy */;
};
- 72B71BC10EA8092700BFE986 /* PBXTargetDependency */ = {
+ 726056270EA808B700D65FE7 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = FC59A0CD0E8C8A5C00D41150 /* launchproxy */;
- targetProxy = 72B71BC00EA8092700BFE986 /* PBXContainerItemProxy */;
+ targetProxy = 726056260EA808B700D65FE7 /* PBXContainerItemProxy */;
};
- 72B71BC30EA8092F00BFE986 /* PBXTargetDependency */ = {
+ 726056290EA808B900D65FE7 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = FCD7132A0E95D64D001B0111 /* wait4path */;
- targetProxy = 72B71BC20EA8092F00BFE986 /* PBXContainerItemProxy */;
+ targetProxy = 726056280EA808B900D65FE7 /* PBXContainerItemProxy */;
};
FC59A07E0E8C88C100D41150 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
- 72B71BBB0EA8091400BFE986 /* Release */ = {
+ 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;
+ INSTALL_PATH = /sbin;
+ PREBINDING = NO;
+ 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 = {
+ 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;
+ PREBINDING = NO;
+ PRODUCT_NAME = launchctl;
+ STRIP_STYLE = debugging;
+ VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 726056210EA8088D00D65FE7 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = YES;
OTHER_CFLAGS = (
"-D__MigTypeCheck=1",
"-Dmig_external=__private_extern__",
+ "-D_DARWIN_USE_64_BIT_INODE=1",
);
WARNING_CFLAGS = (
"-Wall",
INSTALL_PATH = /sbin;
PREBINDING = NO;
PRODUCT_NAME = launchd;
+ STRIP_STYLE = debugging;
+ VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
ZERO_LINK = NO;
};
name = Release;
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
- ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "ppc i386 ppc64 x86_64";
BUILD_VARIANTS = (
normal,
debug,
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ INSTALLHDRS_SCRIPT_PHASE = YES;
INSTALL_PATH = /usr/local/lib/system;
OTHER_CFLAGS = (
"-D__MigTypeCheck=1",
"-Dmig_external=__private_extern__",
"-D__DARWIN_NON_CANCELABLE=1",
+ "-D_DARWIN_USE_64_BIT_INODE=1",
);
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 = __;
};
INSTALL_PATH = /bin;
PREBINDING = NO;
PRODUCT_NAME = launchctl;
+ STRIP_STYLE = debugging;
+ VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
ZERO_LINK = NO;
};
name = Release;
INSTALL_PATH = /sbin;
PREBINDING = NO;
PRODUCT_NAME = SystemStarter;
+ STRIP_STYLE = debugging;
+ VALID_ARCHS = "i386 ppc ppc64 ppc7400 ppc970 x86_64";
ZERO_LINK = NO;
};
name = Release;
INSTALL_PATH = /usr/libexec;
PREBINDING = NO;
PRODUCT_NAME = launchproxy;
+ STRIP_STYLE = debugging;
+ VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
ZERO_LINK = NO;
};
name = Release;
INSTALL_PATH = /bin;
PREBINDING = NO;
PRODUCT_NAME = wait4path;
+ STRIP_STYLE = debugging;
+ VALID_ARCHS = "armv5 armv6 armv7 i386 ppc ppc64 ppc7400 ppc970 x86_64";
ZERO_LINK = NO;
};
name = Release;
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
- 72B71BC40EA8095200BFE986 /* Build configuration list for PBXAggregateTarget "embedded" */ = {
+ 4B10F1D10F43BE7E00875782 /* Build configuration list for PBXNativeTarget "launchd-embedded" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4B10F1D20F43BE7E00875782 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4B10F1F10F43BF5C00875782 /* Build configuration list for PBXNativeTarget "launchctl-embedded" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4B10F1F20F43BF5C00875782 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7260562B0EA808D800D65FE7 /* Build configuration list for PBXAggregateTarget "embedded" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 72B71BBB0EA8091400BFE986 /* Release */,
+ 726056210EA8088D00D65FE7 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
+++ /dev/null
-AM_CFLAGS = -no-cpp-precomp -isysroot $(SDKROOT) -F$(SDKROOT)/System/Library/PrivateFrameworks -Wall -Wextra -Waggregate-return -Wshadow -Wmissing-prototypes -Wmissing-declarations -Werror -D__MigTypeCheck=1 -fvisibility=hidden -Dmig_external=__private_extern__
-
-AM_LDFLAGS = -Wl,-syslibroot,$(SDKROOT)
-
-CLEANFILES = protocol_vproc.h protocol_vprocServer.c protocol_vprocUser.c protocol_vprocServer.h \
- launchd_internal.h launchd_internalServer.h launchd_internalServer.c launchd_internalUser.c \
- notifyServer.c notifyServer.h job_replyUser.c job_reply.h __version.c mach_excServer.c mach_excServer.h
-
-protocol_vproc.h protocol_vprocServer.c protocol_vprocUser.c protocol_vprocServer.h: $(srcdir)/protocol_job.defs
- mig $(MIGFLAGS) -sheader protocol_vprocServer.h $(srcdir)/protocol_job.defs
-
-if LIBS_ONLY
-
-noinst_LIBRARIES = liblaunch.a liblaunch_profile.a
-
-liblaunch_a_CFLAGS = -D__DARWIN_NON_CANCELABLE=1 $(AM_CFLAGS)
-liblaunch_a_SOURCES = liblaunch.c libvproc.c libbootstrap.c protocol_vprocUser.c __version.c
-
-liblaunch_profile_a_CFLAGS = -pg -D__DARWIN_NON_CANCELABLE=1 $(AM_CFLAGS)
-liblaunch_profile_a_SOURCES = liblaunch.c libvproc.c libbootstrap.c protocol_vprocUser.c __version.c
-
-$(srcdir)/libvproc.c:: protocol_vproc.h
-
-$(srcdir)/protocol_vprocUser.c:: protocol_vproc.h
-
-__version.c:
- /Developer/Makefiles/bin/version.pl launchd_libs > $@
-
-
-install-data-hook:
- mkdir -p $(DESTDIR)/usr/local/lib/system
- cp liblaunch.a $(DESTDIR)/usr/local/lib/system
- cp liblaunch.a $(DESTDIR)/usr/local/lib/system/liblaunch_debug.a
- cp liblaunch_profile.a $(DESTDIR)/usr/local/lib/system/liblaunch_profile.a
-
-else
-
-bin_PROGRAMS = launchctl wait4path
-if DO_EMBEDDED_MAGIC
-sbin_PROGRAMS = launchd
-else
-sbin_PROGRAMS = launchd SystemStarter
-endif
-libexec_PROGRAMS = launchproxy
-
-sysconf_DATA = hostconfig rc.common rc.netboot
-
-launchctl_CFLAGS = $(AM_CFLAGS) -I$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders
-launchctl_LDFLAGS = $(AM_LDFLAGS) -framework CoreFoundation -framework IOKit $(LIBS_SECURITY) -weak_library /usr/lib/libedit.dylib
-
-if DO_EMBEDDED_MAGIC
-else
-SystemStarter_CFLAGS = -mdynamic-no-pic $(AM_CFLAGS)
-SystemStarter_LDFLAGS = $(AM_LDFLAGS) -framework CoreFoundation -framework IOKit
-SystemStarter_SOURCES = StartupItems.c IPC.c SystemStarter.c
-endif
-
-launchd_CFLAGS = -mdynamic-no-pic $(AM_CFLAGS) -Wno-unused-parameter
-launchd_LDFLAGS = $(AM_LDFLAGS) -lbsm
-launchd_SOURCES = launchd.c launchd_core_logic.c launchd_unix_ipc.c protocol_vprocServer.c notifyServer.c launchd_internalUser.c launchd_internalServer.c job_replyUser.c launchd_runtime.c launchd_runtime_kill.c mach_excServer.c
-
-launchd_runtime.c:: notifyServer.h launchd_internal.h mach_excServer.h
-launchd_core_logic.c:: protocol_vproc.h job_reply.h protocol_vprocServer.h
-
-launchproxy_LDFLAGS = $(AM_LDFLAGS) $(WEAKLIBS_SECURITY)
-
-notifyServer.c notifyServer.h: /usr/include/mach/notify.defs
- mig $(MIGFLAGS) -header /dev/null -user /dev/null -sheader notifyServer.h /usr/include/mach/notify.defs
-
-mach_excServer.c mach_excServer.h: /usr/include/mach/mach_exc.defs
- mig $(MIGFLAGS) -header /dev/null -user /dev/null -sheader mach_excServer.h /usr/include/mach/mach_exc.defs
-
-job_replyUser.c job_reply.h: $(srcdir)/protocol_job_reply.defs
- mig $(MIGFLAGS) -sheader /dev/null -server /dev/null $(srcdir)/protocol_job_reply.defs
-
-launchd_internal.h launchd_internalServer.c launchd_internalUser.c launchd_internalServer.h: $(srcdir)/launchd_internal.defs
- mig $(MIGFLAGS) -sheader launchd_internalServer.h $(srcdir)/launchd_internal.defs
-
-
-man1_MANS = wait4path.1 launchctl.1
-
-man5_MANS = launchd.plist.5 launchd.conf.5
-
-if DO_EMBEDDED_MAGIC
-man8_MANS = launchd.8 launchproxy.8
-else
-man8_MANS = StartupItemContext.8 SystemStarter.8 rc.8 launchd.8 launchproxy.8
-endif
-
-install-data-hook:
- mkdir -p $(DESTDIR)/usr/libexec
- mkdir -p $(DESTDIR)/usr/include/servers
- mkdir -p $(DESTDIR)/usr/local/include
- mkdir -p $(DESTDIR)/$(sysconfdir)/mach_init.d
- mkdir -p $(DESTDIR)/$(sysconfdir)/mach_init_per_user.d
- mkdir -p $(DESTDIR)/$(sysconfdir)/mach_init_per_login_session.d
- mkdir -p $(DESTDIR)/Library/LaunchDaemons
- mkdir -p $(DESTDIR)/Library/LaunchAgents
- mkdir -p $(DESTDIR)/System/Library/LaunchAgents
- mkdir -p $(DESTDIR)/System/Library/LaunchDaemons
- cp $(srcdir)/liblaunch_public.h $(DESTDIR)/usr/include/launch.h
- cp $(srcdir)/libvproc_public.h $(DESTDIR)/usr/include/vproc.h
- cp $(srcdir)/libbootstrap_public.h $(DESTDIR)/usr/include/servers/bootstrap.h
- cp $(srcdir)/libbootstrap_public.h $(DESTDIR)/usr/include/servers/bootstrap_defs.h
- cp $(srcdir)/libbootstrap_private.h $(DESTDIR)/usr/local/include/bootstrap_priv.h
- cp $(srcdir)/liblaunch_private.h $(DESTDIR)/usr/local/include/launch_priv.h
- cp $(srcdir)/libvproc_private.h $(DESTDIR)/usr/local/include/vproc_priv.h
- cp $(srcdir)/reboot2.h $(DESTDIR)/usr/local/include/reboot2.h
-if DO_EMBEDDED_MAGIC
-else
- cp $(srcdir)/StartupItemContext $(DESTDIR)/usr/libexec
- cp $(srcdir)/com.apple.SystemStarter.plist $(DESTDIR)/System/Library/LaunchDaemons
-endif
-
-endif
+++ /dev/null
-# Makefile.in generated by automake 1.10 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-
-
-VPATH = @srcdir@
-pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-@LIBS_ONLY_FALSE@bin_PROGRAMS = launchctl$(EXEEXT) wait4path$(EXEEXT)
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@sbin_PROGRAMS = \
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@ launchd$(EXEEXT) \
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@ SystemStarter$(EXEEXT)
-@DO_EMBEDDED_MAGIC_TRUE@@LIBS_ONLY_FALSE@sbin_PROGRAMS = \
-@DO_EMBEDDED_MAGIC_TRUE@@LIBS_ONLY_FALSE@ launchd$(EXEEXT)
-@LIBS_ONLY_FALSE@libexec_PROGRAMS = launchproxy$(EXEEXT)
-subdir = src
-DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
- $(srcdir)/config.h.in
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
- $(ACLOCAL_M4)
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
-CONFIG_HEADER = config.h
-CONFIG_CLEAN_FILES =
-LIBRARIES = $(noinst_LIBRARIES)
-AR = ar
-ARFLAGS = cru
-liblaunch_a_AR = $(AR) $(ARFLAGS)
-liblaunch_a_LIBADD =
-am__liblaunch_a_SOURCES_DIST = liblaunch.c libvproc.c libbootstrap.c \
- protocol_vprocUser.c __version.c
-@LIBS_ONLY_TRUE@am_liblaunch_a_OBJECTS = \
-@LIBS_ONLY_TRUE@ liblaunch_a-liblaunch.$(OBJEXT) \
-@LIBS_ONLY_TRUE@ liblaunch_a-libvproc.$(OBJEXT) \
-@LIBS_ONLY_TRUE@ liblaunch_a-libbootstrap.$(OBJEXT) \
-@LIBS_ONLY_TRUE@ liblaunch_a-protocol_vprocUser.$(OBJEXT) \
-@LIBS_ONLY_TRUE@ liblaunch_a-__version.$(OBJEXT)
-liblaunch_a_OBJECTS = $(am_liblaunch_a_OBJECTS)
-liblaunch_profile_a_AR = $(AR) $(ARFLAGS)
-liblaunch_profile_a_LIBADD =
-am__liblaunch_profile_a_SOURCES_DIST = liblaunch.c libvproc.c \
- libbootstrap.c protocol_vprocUser.c __version.c
-@LIBS_ONLY_TRUE@am_liblaunch_profile_a_OBJECTS = \
-@LIBS_ONLY_TRUE@ liblaunch_profile_a-liblaunch.$(OBJEXT) \
-@LIBS_ONLY_TRUE@ liblaunch_profile_a-libvproc.$(OBJEXT) \
-@LIBS_ONLY_TRUE@ liblaunch_profile_a-libbootstrap.$(OBJEXT) \
-@LIBS_ONLY_TRUE@ liblaunch_profile_a-protocol_vprocUser.$(OBJEXT) \
-@LIBS_ONLY_TRUE@ liblaunch_profile_a-__version.$(OBJEXT)
-liblaunch_profile_a_OBJECTS = $(am_liblaunch_profile_a_OBJECTS)
-am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" \
- "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" \
- "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" \
- "$(DESTDIR)$(sysconfdir)"
-binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
-libexecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
-sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
-PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS) $(sbin_PROGRAMS)
-am__SystemStarter_SOURCES_DIST = StartupItems.c IPC.c SystemStarter.c
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@am_SystemStarter_OBJECTS = SystemStarter-StartupItems.$(OBJEXT) \
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@ SystemStarter-IPC.$(OBJEXT) \
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@ SystemStarter-SystemStarter.$(OBJEXT)
-SystemStarter_OBJECTS = $(am_SystemStarter_OBJECTS)
-SystemStarter_LDADD = $(LDADD)
-SystemStarter_LINK = $(CCLD) $(SystemStarter_CFLAGS) $(CFLAGS) \
- $(SystemStarter_LDFLAGS) $(LDFLAGS) -o $@
-launchctl_SOURCES = launchctl.c
-launchctl_OBJECTS = launchctl-launchctl.$(OBJEXT)
-launchctl_LDADD = $(LDADD)
-launchctl_LINK = $(CCLD) $(launchctl_CFLAGS) $(CFLAGS) \
- $(launchctl_LDFLAGS) $(LDFLAGS) -o $@
-am__launchd_SOURCES_DIST = launchd.c launchd_core_logic.c \
- launchd_unix_ipc.c protocol_vprocServer.c notifyServer.c \
- launchd_internalUser.c launchd_internalServer.c \
- job_replyUser.c launchd_runtime.c launchd_runtime_kill.c \
- mach_excServer.c
-@LIBS_ONLY_FALSE@am_launchd_OBJECTS = launchd-launchd.$(OBJEXT) \
-@LIBS_ONLY_FALSE@ launchd-launchd_core_logic.$(OBJEXT) \
-@LIBS_ONLY_FALSE@ launchd-launchd_unix_ipc.$(OBJEXT) \
-@LIBS_ONLY_FALSE@ launchd-protocol_vprocServer.$(OBJEXT) \
-@LIBS_ONLY_FALSE@ launchd-notifyServer.$(OBJEXT) \
-@LIBS_ONLY_FALSE@ launchd-launchd_internalUser.$(OBJEXT) \
-@LIBS_ONLY_FALSE@ launchd-launchd_internalServer.$(OBJEXT) \
-@LIBS_ONLY_FALSE@ launchd-job_replyUser.$(OBJEXT) \
-@LIBS_ONLY_FALSE@ launchd-launchd_runtime.$(OBJEXT) \
-@LIBS_ONLY_FALSE@ launchd-launchd_runtime_kill.$(OBJEXT) \
-@LIBS_ONLY_FALSE@ launchd-mach_excServer.$(OBJEXT)
-launchd_OBJECTS = $(am_launchd_OBJECTS)
-launchd_LDADD = $(LDADD)
-launchd_LINK = $(CCLD) $(launchd_CFLAGS) $(CFLAGS) $(launchd_LDFLAGS) \
- $(LDFLAGS) -o $@
-launchproxy_SOURCES = launchproxy.c
-launchproxy_OBJECTS = launchproxy.$(OBJEXT)
-launchproxy_LDADD = $(LDADD)
-launchproxy_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(launchproxy_LDFLAGS) $(LDFLAGS) -o $@
-wait4path_SOURCES = wait4path.c
-wait4path_OBJECTS = wait4path.$(OBJEXT)
-wait4path_LDADD = $(LDADD)
-DEFAULT_INCLUDES = -I.@am__isrc@
-depcomp = $(SHELL) $(top_srcdir)/depcomp
-am__depfiles_maybe = depfiles
-COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
- $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-CCLD = $(CC)
-LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
-SOURCES = $(liblaunch_a_SOURCES) $(liblaunch_profile_a_SOURCES) \
- $(SystemStarter_SOURCES) launchctl.c $(launchd_SOURCES) \
- launchproxy.c wait4path.c
-DIST_SOURCES = $(am__liblaunch_a_SOURCES_DIST) \
- $(am__liblaunch_profile_a_SOURCES_DIST) \
- $(am__SystemStarter_SOURCES_DIST) launchctl.c \
- $(am__launchd_SOURCES_DIST) launchproxy.c wait4path.c
-man1dir = $(mandir)/man1
-man5dir = $(mandir)/man5
-man8dir = $(mandir)/man8
-NROFF = nroff
-MANS = $(man1_MANS) $(man5_MANS) $(man8_MANS)
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
- $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
- *) f=$$p;; \
- esac;
-am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
-sysconfDATA_INSTALL = $(INSTALL_DATA)
-DATA = $(sysconf_DATA)
-ETAGS = etags
-CTAGS = ctags
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-ACLOCAL = @ACLOCAL@
-ALLOCA = @ALLOCA@
-AMTAR = @AMTAR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-GREP = @GREP@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-LDFLAGS = @LDFLAGS@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBS_SECURITY = @LIBS_SECURITY@
-LTLIBOBJS = @LTLIBOBJS@
-MAKEINFO = @MAKEINFO@
-MKDIR_P = @MKDIR_P@
-OBJEXT = @OBJEXT@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-STRIP = @STRIP@
-VERSION = @VERSION@
-WEAKLIBS_SECURITY = @WEAKLIBS_SECURITY@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_CC = @ac_ct_CC@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build_alias = @build_alias@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host_alias = @host_alias@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-target_alias = @target_alias@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-AM_CFLAGS = -no-cpp-precomp -isysroot $(SDKROOT) -F$(SDKROOT)/System/Library/PrivateFrameworks -Wall -Wextra -Waggregate-return -Wshadow -Wmissing-prototypes -Wmissing-declarations -Werror -D__MigTypeCheck=1 -fvisibility=hidden -Dmig_external=__private_extern__
-AM_LDFLAGS = -Wl,-syslibroot,$(SDKROOT)
-CLEANFILES = protocol_vproc.h protocol_vprocServer.c protocol_vprocUser.c protocol_vprocServer.h \
- launchd_internal.h launchd_internalServer.h launchd_internalServer.c launchd_internalUser.c \
- notifyServer.c notifyServer.h job_replyUser.c job_reply.h __version.c mach_excServer.c mach_excServer.h
-
-@LIBS_ONLY_TRUE@noinst_LIBRARIES = liblaunch.a liblaunch_profile.a
-@LIBS_ONLY_TRUE@liblaunch_a_CFLAGS = -D__DARWIN_NON_CANCELABLE=1 $(AM_CFLAGS)
-@LIBS_ONLY_TRUE@liblaunch_a_SOURCES = liblaunch.c libvproc.c libbootstrap.c protocol_vprocUser.c __version.c
-@LIBS_ONLY_TRUE@liblaunch_profile_a_CFLAGS = -pg -D__DARWIN_NON_CANCELABLE=1 $(AM_CFLAGS)
-@LIBS_ONLY_TRUE@liblaunch_profile_a_SOURCES = liblaunch.c libvproc.c libbootstrap.c protocol_vprocUser.c __version.c
-@LIBS_ONLY_FALSE@sysconf_DATA = hostconfig rc.common rc.netboot
-@LIBS_ONLY_FALSE@launchctl_CFLAGS = $(AM_CFLAGS) -I$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders
-@LIBS_ONLY_FALSE@launchctl_LDFLAGS = $(AM_LDFLAGS) -framework CoreFoundation -framework IOKit $(LIBS_SECURITY) -weak_library /usr/lib/libedit.dylib
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@SystemStarter_CFLAGS = -mdynamic-no-pic $(AM_CFLAGS)
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@SystemStarter_LDFLAGS = $(AM_LDFLAGS) -framework CoreFoundation -framework IOKit
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@SystemStarter_SOURCES = StartupItems.c IPC.c SystemStarter.c
-@LIBS_ONLY_FALSE@launchd_CFLAGS = -mdynamic-no-pic $(AM_CFLAGS) -Wno-unused-parameter
-@LIBS_ONLY_FALSE@launchd_LDFLAGS = $(AM_LDFLAGS) -lbsm
-@LIBS_ONLY_FALSE@launchd_SOURCES = launchd.c launchd_core_logic.c launchd_unix_ipc.c protocol_vprocServer.c notifyServer.c launchd_internalUser.c launchd_internalServer.c job_replyUser.c launchd_runtime.c launchd_runtime_kill.c mach_excServer.c
-@LIBS_ONLY_FALSE@launchproxy_LDFLAGS = $(AM_LDFLAGS) $(WEAKLIBS_SECURITY)
-@LIBS_ONLY_FALSE@man1_MANS = wait4path.1 launchctl.1
-@LIBS_ONLY_FALSE@man5_MANS = launchd.plist.5 launchd.conf.5
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@man8_MANS = StartupItemContext.8 SystemStarter.8 rc.8 launchd.8 launchproxy.8
-@DO_EMBEDDED_MAGIC_TRUE@@LIBS_ONLY_FALSE@man8_MANS = launchd.8 launchproxy.8
-all: config.h
- $(MAKE) $(AM_MAKEFLAGS) all-am
-
-.SUFFIXES:
-.SUFFIXES: .c .o .obj
-$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
- @for dep in $?; do \
- case '$(am__configure_deps)' in \
- *$$dep*) \
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
- && exit 0; \
- exit 1;; \
- esac; \
- done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
- cd $(top_srcdir) && \
- $(AUTOMAKE) --gnu src/Makefile
-.PRECIOUS: Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
- @case '$?' in \
- *config.status*) \
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
- *) \
- echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
- cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
- esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: $(am__configure_deps)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): $(am__aclocal_m4_deps)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-config.h: stamp-h1
- @if test ! -f $@; then \
- rm -f stamp-h1; \
- $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
- else :; fi
-
-stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
- @rm -f stamp-h1
- cd $(top_builddir) && $(SHELL) ./config.status src/config.h
-$(srcdir)/config.h.in: $(am__configure_deps)
- cd $(top_srcdir) && $(AUTOHEADER)
- rm -f stamp-h1
- touch $@
-
-distclean-hdr:
- -rm -f config.h stamp-h1
-
-clean-noinstLIBRARIES:
- -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
-liblaunch.a: $(liblaunch_a_OBJECTS) $(liblaunch_a_DEPENDENCIES)
- -rm -f liblaunch.a
- $(liblaunch_a_AR) liblaunch.a $(liblaunch_a_OBJECTS) $(liblaunch_a_LIBADD)
- $(RANLIB) liblaunch.a
-liblaunch_profile.a: $(liblaunch_profile_a_OBJECTS) $(liblaunch_profile_a_DEPENDENCIES)
- -rm -f liblaunch_profile.a
- $(liblaunch_profile_a_AR) liblaunch_profile.a $(liblaunch_profile_a_OBJECTS) $(liblaunch_profile_a_LIBADD)
- $(RANLIB) liblaunch_profile.a
-install-binPROGRAMS: $(bin_PROGRAMS)
- @$(NORMAL_INSTALL)
- test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
- @list='$(bin_PROGRAMS)'; for p in $$list; do \
- p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
- if test -f $$p \
- ; then \
- f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
- echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
- $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
- else :; fi; \
- done
-
-uninstall-binPROGRAMS:
- @$(NORMAL_UNINSTALL)
- @list='$(bin_PROGRAMS)'; for p in $$list; do \
- f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
- echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
- rm -f "$(DESTDIR)$(bindir)/$$f"; \
- done
-
-clean-binPROGRAMS:
- -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
-install-libexecPROGRAMS: $(libexec_PROGRAMS)
- @$(NORMAL_INSTALL)
- test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)"
- @list='$(libexec_PROGRAMS)'; for p in $$list; do \
- p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
- if test -f $$p \
- ; then \
- f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
- echo " $(INSTALL_PROGRAM_ENV) $(libexecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(libexecdir)/$$f'"; \
- $(INSTALL_PROGRAM_ENV) $(libexecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(libexecdir)/$$f" || exit 1; \
- else :; fi; \
- done
-
-uninstall-libexecPROGRAMS:
- @$(NORMAL_UNINSTALL)
- @list='$(libexec_PROGRAMS)'; for p in $$list; do \
- f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
- echo " rm -f '$(DESTDIR)$(libexecdir)/$$f'"; \
- rm -f "$(DESTDIR)$(libexecdir)/$$f"; \
- done
-
-clean-libexecPROGRAMS:
- -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS)
-install-sbinPROGRAMS: $(sbin_PROGRAMS)
- @$(NORMAL_INSTALL)
- test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
- @list='$(sbin_PROGRAMS)'; for p in $$list; do \
- p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
- if test -f $$p \
- ; then \
- f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
- echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
- $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \
- else :; fi; \
- done
-
-uninstall-sbinPROGRAMS:
- @$(NORMAL_UNINSTALL)
- @list='$(sbin_PROGRAMS)'; for p in $$list; do \
- f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
- echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
- rm -f "$(DESTDIR)$(sbindir)/$$f"; \
- done
-
-clean-sbinPROGRAMS:
- -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
-SystemStarter$(EXEEXT): $(SystemStarter_OBJECTS) $(SystemStarter_DEPENDENCIES)
- @rm -f SystemStarter$(EXEEXT)
- $(SystemStarter_LINK) $(SystemStarter_OBJECTS) $(SystemStarter_LDADD) $(LIBS)
-launchctl$(EXEEXT): $(launchctl_OBJECTS) $(launchctl_DEPENDENCIES)
- @rm -f launchctl$(EXEEXT)
- $(launchctl_LINK) $(launchctl_OBJECTS) $(launchctl_LDADD) $(LIBS)
-launchd$(EXEEXT): $(launchd_OBJECTS) $(launchd_DEPENDENCIES)
- @rm -f launchd$(EXEEXT)
- $(launchd_LINK) $(launchd_OBJECTS) $(launchd_LDADD) $(LIBS)
-launchproxy$(EXEEXT): $(launchproxy_OBJECTS) $(launchproxy_DEPENDENCIES)
- @rm -f launchproxy$(EXEEXT)
- $(launchproxy_LINK) $(launchproxy_OBJECTS) $(launchproxy_LDADD) $(LIBS)
-wait4path$(EXEEXT): $(wait4path_OBJECTS) $(wait4path_DEPENDENCIES)
- @rm -f wait4path$(EXEEXT)
- $(LINK) $(wait4path_OBJECTS) $(wait4path_LDADD) $(LIBS)
-
-mostlyclean-compile:
- -rm -f *.$(OBJEXT)
-
-distclean-compile:
- -rm -f *.tab.c
-
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemStarter-IPC.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemStarter-StartupItems.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemStarter-SystemStarter.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchctl-launchctl.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-job_replyUser.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-launchd.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-launchd_core_logic.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-launchd_internalServer.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-launchd_internalUser.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-launchd_runtime.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-launchd_runtime_kill.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-launchd_unix_ipc.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-mach_excServer.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-notifyServer.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-protocol_vprocServer.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchproxy.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch_a-__version.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch_a-libbootstrap.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch_a-liblaunch.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch_a-libvproc.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch_a-protocol_vprocUser.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch_profile_a-__version.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch_profile_a-libbootstrap.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch_profile_a-liblaunch.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch_profile_a-libvproc.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch_profile_a-protocol_vprocUser.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wait4path.Po@am__quote@
-
-.c.o:
-@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(COMPILE) -c $<
-
-.c.obj:
-@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
-
-liblaunch_a-liblaunch.o: liblaunch.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -MT liblaunch_a-liblaunch.o -MD -MP -MF $(DEPDIR)/liblaunch_a-liblaunch.Tpo -c -o liblaunch_a-liblaunch.o `test -f 'liblaunch.c' || echo '$(srcdir)/'`liblaunch.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_a-liblaunch.Tpo $(DEPDIR)/liblaunch_a-liblaunch.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='liblaunch.c' object='liblaunch_a-liblaunch.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -c -o liblaunch_a-liblaunch.o `test -f 'liblaunch.c' || echo '$(srcdir)/'`liblaunch.c
-
-liblaunch_a-liblaunch.obj: liblaunch.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -MT liblaunch_a-liblaunch.obj -MD -MP -MF $(DEPDIR)/liblaunch_a-liblaunch.Tpo -c -o liblaunch_a-liblaunch.obj `if test -f 'liblaunch.c'; then $(CYGPATH_W) 'liblaunch.c'; else $(CYGPATH_W) '$(srcdir)/liblaunch.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_a-liblaunch.Tpo $(DEPDIR)/liblaunch_a-liblaunch.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='liblaunch.c' object='liblaunch_a-liblaunch.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -c -o liblaunch_a-liblaunch.obj `if test -f 'liblaunch.c'; then $(CYGPATH_W) 'liblaunch.c'; else $(CYGPATH_W) '$(srcdir)/liblaunch.c'; fi`
-
-liblaunch_a-libvproc.o: libvproc.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -MT liblaunch_a-libvproc.o -MD -MP -MF $(DEPDIR)/liblaunch_a-libvproc.Tpo -c -o liblaunch_a-libvproc.o `test -f 'libvproc.c' || echo '$(srcdir)/'`libvproc.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_a-libvproc.Tpo $(DEPDIR)/liblaunch_a-libvproc.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libvproc.c' object='liblaunch_a-libvproc.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -c -o liblaunch_a-libvproc.o `test -f 'libvproc.c' || echo '$(srcdir)/'`libvproc.c
-
-liblaunch_a-libvproc.obj: libvproc.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -MT liblaunch_a-libvproc.obj -MD -MP -MF $(DEPDIR)/liblaunch_a-libvproc.Tpo -c -o liblaunch_a-libvproc.obj `if test -f 'libvproc.c'; then $(CYGPATH_W) 'libvproc.c'; else $(CYGPATH_W) '$(srcdir)/libvproc.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_a-libvproc.Tpo $(DEPDIR)/liblaunch_a-libvproc.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libvproc.c' object='liblaunch_a-libvproc.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -c -o liblaunch_a-libvproc.obj `if test -f 'libvproc.c'; then $(CYGPATH_W) 'libvproc.c'; else $(CYGPATH_W) '$(srcdir)/libvproc.c'; fi`
-
-liblaunch_a-libbootstrap.o: libbootstrap.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -MT liblaunch_a-libbootstrap.o -MD -MP -MF $(DEPDIR)/liblaunch_a-libbootstrap.Tpo -c -o liblaunch_a-libbootstrap.o `test -f 'libbootstrap.c' || echo '$(srcdir)/'`libbootstrap.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_a-libbootstrap.Tpo $(DEPDIR)/liblaunch_a-libbootstrap.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libbootstrap.c' object='liblaunch_a-libbootstrap.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -c -o liblaunch_a-libbootstrap.o `test -f 'libbootstrap.c' || echo '$(srcdir)/'`libbootstrap.c
-
-liblaunch_a-libbootstrap.obj: libbootstrap.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -MT liblaunch_a-libbootstrap.obj -MD -MP -MF $(DEPDIR)/liblaunch_a-libbootstrap.Tpo -c -o liblaunch_a-libbootstrap.obj `if test -f 'libbootstrap.c'; then $(CYGPATH_W) 'libbootstrap.c'; else $(CYGPATH_W) '$(srcdir)/libbootstrap.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_a-libbootstrap.Tpo $(DEPDIR)/liblaunch_a-libbootstrap.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libbootstrap.c' object='liblaunch_a-libbootstrap.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -c -o liblaunch_a-libbootstrap.obj `if test -f 'libbootstrap.c'; then $(CYGPATH_W) 'libbootstrap.c'; else $(CYGPATH_W) '$(srcdir)/libbootstrap.c'; fi`
-
-liblaunch_a-protocol_vprocUser.o: protocol_vprocUser.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -MT liblaunch_a-protocol_vprocUser.o -MD -MP -MF $(DEPDIR)/liblaunch_a-protocol_vprocUser.Tpo -c -o liblaunch_a-protocol_vprocUser.o `test -f 'protocol_vprocUser.c' || echo '$(srcdir)/'`protocol_vprocUser.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_a-protocol_vprocUser.Tpo $(DEPDIR)/liblaunch_a-protocol_vprocUser.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='protocol_vprocUser.c' object='liblaunch_a-protocol_vprocUser.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -c -o liblaunch_a-protocol_vprocUser.o `test -f 'protocol_vprocUser.c' || echo '$(srcdir)/'`protocol_vprocUser.c
-
-liblaunch_a-protocol_vprocUser.obj: protocol_vprocUser.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -MT liblaunch_a-protocol_vprocUser.obj -MD -MP -MF $(DEPDIR)/liblaunch_a-protocol_vprocUser.Tpo -c -o liblaunch_a-protocol_vprocUser.obj `if test -f 'protocol_vprocUser.c'; then $(CYGPATH_W) 'protocol_vprocUser.c'; else $(CYGPATH_W) '$(srcdir)/protocol_vprocUser.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_a-protocol_vprocUser.Tpo $(DEPDIR)/liblaunch_a-protocol_vprocUser.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='protocol_vprocUser.c' object='liblaunch_a-protocol_vprocUser.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -c -o liblaunch_a-protocol_vprocUser.obj `if test -f 'protocol_vprocUser.c'; then $(CYGPATH_W) 'protocol_vprocUser.c'; else $(CYGPATH_W) '$(srcdir)/protocol_vprocUser.c'; fi`
-
-liblaunch_a-__version.o: __version.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -MT liblaunch_a-__version.o -MD -MP -MF $(DEPDIR)/liblaunch_a-__version.Tpo -c -o liblaunch_a-__version.o `test -f '__version.c' || echo '$(srcdir)/'`__version.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_a-__version.Tpo $(DEPDIR)/liblaunch_a-__version.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='__version.c' object='liblaunch_a-__version.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -c -o liblaunch_a-__version.o `test -f '__version.c' || echo '$(srcdir)/'`__version.c
-
-liblaunch_a-__version.obj: __version.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -MT liblaunch_a-__version.obj -MD -MP -MF $(DEPDIR)/liblaunch_a-__version.Tpo -c -o liblaunch_a-__version.obj `if test -f '__version.c'; then $(CYGPATH_W) '__version.c'; else $(CYGPATH_W) '$(srcdir)/__version.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_a-__version.Tpo $(DEPDIR)/liblaunch_a-__version.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='__version.c' object='liblaunch_a-__version.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_a_CFLAGS) $(CFLAGS) -c -o liblaunch_a-__version.obj `if test -f '__version.c'; then $(CYGPATH_W) '__version.c'; else $(CYGPATH_W) '$(srcdir)/__version.c'; fi`
-
-liblaunch_profile_a-liblaunch.o: liblaunch.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -MT liblaunch_profile_a-liblaunch.o -MD -MP -MF $(DEPDIR)/liblaunch_profile_a-liblaunch.Tpo -c -o liblaunch_profile_a-liblaunch.o `test -f 'liblaunch.c' || echo '$(srcdir)/'`liblaunch.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_profile_a-liblaunch.Tpo $(DEPDIR)/liblaunch_profile_a-liblaunch.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='liblaunch.c' object='liblaunch_profile_a-liblaunch.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-liblaunch.o `test -f 'liblaunch.c' || echo '$(srcdir)/'`liblaunch.c
-
-liblaunch_profile_a-liblaunch.obj: liblaunch.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -MT liblaunch_profile_a-liblaunch.obj -MD -MP -MF $(DEPDIR)/liblaunch_profile_a-liblaunch.Tpo -c -o liblaunch_profile_a-liblaunch.obj `if test -f 'liblaunch.c'; then $(CYGPATH_W) 'liblaunch.c'; else $(CYGPATH_W) '$(srcdir)/liblaunch.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_profile_a-liblaunch.Tpo $(DEPDIR)/liblaunch_profile_a-liblaunch.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='liblaunch.c' object='liblaunch_profile_a-liblaunch.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-liblaunch.obj `if test -f 'liblaunch.c'; then $(CYGPATH_W) 'liblaunch.c'; else $(CYGPATH_W) '$(srcdir)/liblaunch.c'; fi`
-
-liblaunch_profile_a-libvproc.o: libvproc.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -MT liblaunch_profile_a-libvproc.o -MD -MP -MF $(DEPDIR)/liblaunch_profile_a-libvproc.Tpo -c -o liblaunch_profile_a-libvproc.o `test -f 'libvproc.c' || echo '$(srcdir)/'`libvproc.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_profile_a-libvproc.Tpo $(DEPDIR)/liblaunch_profile_a-libvproc.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libvproc.c' object='liblaunch_profile_a-libvproc.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-libvproc.o `test -f 'libvproc.c' || echo '$(srcdir)/'`libvproc.c
-
-liblaunch_profile_a-libvproc.obj: libvproc.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -MT liblaunch_profile_a-libvproc.obj -MD -MP -MF $(DEPDIR)/liblaunch_profile_a-libvproc.Tpo -c -o liblaunch_profile_a-libvproc.obj `if test -f 'libvproc.c'; then $(CYGPATH_W) 'libvproc.c'; else $(CYGPATH_W) '$(srcdir)/libvproc.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_profile_a-libvproc.Tpo $(DEPDIR)/liblaunch_profile_a-libvproc.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libvproc.c' object='liblaunch_profile_a-libvproc.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-libvproc.obj `if test -f 'libvproc.c'; then $(CYGPATH_W) 'libvproc.c'; else $(CYGPATH_W) '$(srcdir)/libvproc.c'; fi`
-
-liblaunch_profile_a-libbootstrap.o: libbootstrap.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -MT liblaunch_profile_a-libbootstrap.o -MD -MP -MF $(DEPDIR)/liblaunch_profile_a-libbootstrap.Tpo -c -o liblaunch_profile_a-libbootstrap.o `test -f 'libbootstrap.c' || echo '$(srcdir)/'`libbootstrap.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_profile_a-libbootstrap.Tpo $(DEPDIR)/liblaunch_profile_a-libbootstrap.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libbootstrap.c' object='liblaunch_profile_a-libbootstrap.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-libbootstrap.o `test -f 'libbootstrap.c' || echo '$(srcdir)/'`libbootstrap.c
-
-liblaunch_profile_a-libbootstrap.obj: libbootstrap.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -MT liblaunch_profile_a-libbootstrap.obj -MD -MP -MF $(DEPDIR)/liblaunch_profile_a-libbootstrap.Tpo -c -o liblaunch_profile_a-libbootstrap.obj `if test -f 'libbootstrap.c'; then $(CYGPATH_W) 'libbootstrap.c'; else $(CYGPATH_W) '$(srcdir)/libbootstrap.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_profile_a-libbootstrap.Tpo $(DEPDIR)/liblaunch_profile_a-libbootstrap.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libbootstrap.c' object='liblaunch_profile_a-libbootstrap.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-libbootstrap.obj `if test -f 'libbootstrap.c'; then $(CYGPATH_W) 'libbootstrap.c'; else $(CYGPATH_W) '$(srcdir)/libbootstrap.c'; fi`
-
-liblaunch_profile_a-protocol_vprocUser.o: protocol_vprocUser.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -MT liblaunch_profile_a-protocol_vprocUser.o -MD -MP -MF $(DEPDIR)/liblaunch_profile_a-protocol_vprocUser.Tpo -c -o liblaunch_profile_a-protocol_vprocUser.o `test -f 'protocol_vprocUser.c' || echo '$(srcdir)/'`protocol_vprocUser.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_profile_a-protocol_vprocUser.Tpo $(DEPDIR)/liblaunch_profile_a-protocol_vprocUser.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='protocol_vprocUser.c' object='liblaunch_profile_a-protocol_vprocUser.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-protocol_vprocUser.o `test -f 'protocol_vprocUser.c' || echo '$(srcdir)/'`protocol_vprocUser.c
-
-liblaunch_profile_a-protocol_vprocUser.obj: protocol_vprocUser.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -MT liblaunch_profile_a-protocol_vprocUser.obj -MD -MP -MF $(DEPDIR)/liblaunch_profile_a-protocol_vprocUser.Tpo -c -o liblaunch_profile_a-protocol_vprocUser.obj `if test -f 'protocol_vprocUser.c'; then $(CYGPATH_W) 'protocol_vprocUser.c'; else $(CYGPATH_W) '$(srcdir)/protocol_vprocUser.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_profile_a-protocol_vprocUser.Tpo $(DEPDIR)/liblaunch_profile_a-protocol_vprocUser.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='protocol_vprocUser.c' object='liblaunch_profile_a-protocol_vprocUser.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-protocol_vprocUser.obj `if test -f 'protocol_vprocUser.c'; then $(CYGPATH_W) 'protocol_vprocUser.c'; else $(CYGPATH_W) '$(srcdir)/protocol_vprocUser.c'; fi`
-
-liblaunch_profile_a-__version.o: __version.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -MT liblaunch_profile_a-__version.o -MD -MP -MF $(DEPDIR)/liblaunch_profile_a-__version.Tpo -c -o liblaunch_profile_a-__version.o `test -f '__version.c' || echo '$(srcdir)/'`__version.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_profile_a-__version.Tpo $(DEPDIR)/liblaunch_profile_a-__version.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='__version.c' object='liblaunch_profile_a-__version.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-__version.o `test -f '__version.c' || echo '$(srcdir)/'`__version.c
-
-liblaunch_profile_a-__version.obj: __version.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -MT liblaunch_profile_a-__version.obj -MD -MP -MF $(DEPDIR)/liblaunch_profile_a-__version.Tpo -c -o liblaunch_profile_a-__version.obj `if test -f '__version.c'; then $(CYGPATH_W) '__version.c'; else $(CYGPATH_W) '$(srcdir)/__version.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/liblaunch_profile_a-__version.Tpo $(DEPDIR)/liblaunch_profile_a-__version.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='__version.c' object='liblaunch_profile_a-__version.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-__version.obj `if test -f '__version.c'; then $(CYGPATH_W) '__version.c'; else $(CYGPATH_W) '$(srcdir)/__version.c'; fi`
-
-SystemStarter-StartupItems.o: StartupItems.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -MT SystemStarter-StartupItems.o -MD -MP -MF $(DEPDIR)/SystemStarter-StartupItems.Tpo -c -o SystemStarter-StartupItems.o `test -f 'StartupItems.c' || echo '$(srcdir)/'`StartupItems.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/SystemStarter-StartupItems.Tpo $(DEPDIR)/SystemStarter-StartupItems.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='StartupItems.c' object='SystemStarter-StartupItems.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-StartupItems.o `test -f 'StartupItems.c' || echo '$(srcdir)/'`StartupItems.c
-
-SystemStarter-StartupItems.obj: StartupItems.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -MT SystemStarter-StartupItems.obj -MD -MP -MF $(DEPDIR)/SystemStarter-StartupItems.Tpo -c -o SystemStarter-StartupItems.obj `if test -f 'StartupItems.c'; then $(CYGPATH_W) 'StartupItems.c'; else $(CYGPATH_W) '$(srcdir)/StartupItems.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/SystemStarter-StartupItems.Tpo $(DEPDIR)/SystemStarter-StartupItems.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='StartupItems.c' object='SystemStarter-StartupItems.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-StartupItems.obj `if test -f 'StartupItems.c'; then $(CYGPATH_W) 'StartupItems.c'; else $(CYGPATH_W) '$(srcdir)/StartupItems.c'; fi`
-
-SystemStarter-IPC.o: IPC.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -MT SystemStarter-IPC.o -MD -MP -MF $(DEPDIR)/SystemStarter-IPC.Tpo -c -o SystemStarter-IPC.o `test -f 'IPC.c' || echo '$(srcdir)/'`IPC.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/SystemStarter-IPC.Tpo $(DEPDIR)/SystemStarter-IPC.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='IPC.c' object='SystemStarter-IPC.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-IPC.o `test -f 'IPC.c' || echo '$(srcdir)/'`IPC.c
-
-SystemStarter-IPC.obj: IPC.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -MT SystemStarter-IPC.obj -MD -MP -MF $(DEPDIR)/SystemStarter-IPC.Tpo -c -o SystemStarter-IPC.obj `if test -f 'IPC.c'; then $(CYGPATH_W) 'IPC.c'; else $(CYGPATH_W) '$(srcdir)/IPC.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/SystemStarter-IPC.Tpo $(DEPDIR)/SystemStarter-IPC.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='IPC.c' object='SystemStarter-IPC.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-IPC.obj `if test -f 'IPC.c'; then $(CYGPATH_W) 'IPC.c'; else $(CYGPATH_W) '$(srcdir)/IPC.c'; fi`
-
-SystemStarter-SystemStarter.o: SystemStarter.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -MT SystemStarter-SystemStarter.o -MD -MP -MF $(DEPDIR)/SystemStarter-SystemStarter.Tpo -c -o SystemStarter-SystemStarter.o `test -f 'SystemStarter.c' || echo '$(srcdir)/'`SystemStarter.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/SystemStarter-SystemStarter.Tpo $(DEPDIR)/SystemStarter-SystemStarter.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='SystemStarter.c' object='SystemStarter-SystemStarter.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-SystemStarter.o `test -f 'SystemStarter.c' || echo '$(srcdir)/'`SystemStarter.c
-
-SystemStarter-SystemStarter.obj: SystemStarter.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -MT SystemStarter-SystemStarter.obj -MD -MP -MF $(DEPDIR)/SystemStarter-SystemStarter.Tpo -c -o SystemStarter-SystemStarter.obj `if test -f 'SystemStarter.c'; then $(CYGPATH_W) 'SystemStarter.c'; else $(CYGPATH_W) '$(srcdir)/SystemStarter.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/SystemStarter-SystemStarter.Tpo $(DEPDIR)/SystemStarter-SystemStarter.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='SystemStarter.c' object='SystemStarter-SystemStarter.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-SystemStarter.obj `if test -f 'SystemStarter.c'; then $(CYGPATH_W) 'SystemStarter.c'; else $(CYGPATH_W) '$(srcdir)/SystemStarter.c'; fi`
-
-launchctl-launchctl.o: launchctl.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchctl_CFLAGS) $(CFLAGS) -MT launchctl-launchctl.o -MD -MP -MF $(DEPDIR)/launchctl-launchctl.Tpo -c -o launchctl-launchctl.o `test -f 'launchctl.c' || echo '$(srcdir)/'`launchctl.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchctl-launchctl.Tpo $(DEPDIR)/launchctl-launchctl.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchctl.c' object='launchctl-launchctl.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchctl_CFLAGS) $(CFLAGS) -c -o launchctl-launchctl.o `test -f 'launchctl.c' || echo '$(srcdir)/'`launchctl.c
-
-launchctl-launchctl.obj: launchctl.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchctl_CFLAGS) $(CFLAGS) -MT launchctl-launchctl.obj -MD -MP -MF $(DEPDIR)/launchctl-launchctl.Tpo -c -o launchctl-launchctl.obj `if test -f 'launchctl.c'; then $(CYGPATH_W) 'launchctl.c'; else $(CYGPATH_W) '$(srcdir)/launchctl.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchctl-launchctl.Tpo $(DEPDIR)/launchctl-launchctl.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchctl.c' object='launchctl-launchctl.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchctl_CFLAGS) $(CFLAGS) -c -o launchctl-launchctl.obj `if test -f 'launchctl.c'; then $(CYGPATH_W) 'launchctl.c'; else $(CYGPATH_W) '$(srcdir)/launchctl.c'; fi`
-
-launchd-launchd.o: launchd.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd.o -MD -MP -MF $(DEPDIR)/launchd-launchd.Tpo -c -o launchd-launchd.o `test -f 'launchd.c' || echo '$(srcdir)/'`launchd.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd.Tpo $(DEPDIR)/launchd-launchd.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd.c' object='launchd-launchd.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd.o `test -f 'launchd.c' || echo '$(srcdir)/'`launchd.c
-
-launchd-launchd.obj: launchd.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd.obj -MD -MP -MF $(DEPDIR)/launchd-launchd.Tpo -c -o launchd-launchd.obj `if test -f 'launchd.c'; then $(CYGPATH_W) 'launchd.c'; else $(CYGPATH_W) '$(srcdir)/launchd.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd.Tpo $(DEPDIR)/launchd-launchd.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd.c' object='launchd-launchd.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd.obj `if test -f 'launchd.c'; then $(CYGPATH_W) 'launchd.c'; else $(CYGPATH_W) '$(srcdir)/launchd.c'; fi`
-
-launchd-launchd_core_logic.o: launchd_core_logic.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_core_logic.o -MD -MP -MF $(DEPDIR)/launchd-launchd_core_logic.Tpo -c -o launchd-launchd_core_logic.o `test -f 'launchd_core_logic.c' || echo '$(srcdir)/'`launchd_core_logic.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_core_logic.Tpo $(DEPDIR)/launchd-launchd_core_logic.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_core_logic.c' object='launchd-launchd_core_logic.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_core_logic.o `test -f 'launchd_core_logic.c' || echo '$(srcdir)/'`launchd_core_logic.c
-
-launchd-launchd_core_logic.obj: launchd_core_logic.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_core_logic.obj -MD -MP -MF $(DEPDIR)/launchd-launchd_core_logic.Tpo -c -o launchd-launchd_core_logic.obj `if test -f 'launchd_core_logic.c'; then $(CYGPATH_W) 'launchd_core_logic.c'; else $(CYGPATH_W) '$(srcdir)/launchd_core_logic.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_core_logic.Tpo $(DEPDIR)/launchd-launchd_core_logic.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_core_logic.c' object='launchd-launchd_core_logic.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_core_logic.obj `if test -f 'launchd_core_logic.c'; then $(CYGPATH_W) 'launchd_core_logic.c'; else $(CYGPATH_W) '$(srcdir)/launchd_core_logic.c'; fi`
-
-launchd-launchd_unix_ipc.o: launchd_unix_ipc.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_unix_ipc.o -MD -MP -MF $(DEPDIR)/launchd-launchd_unix_ipc.Tpo -c -o launchd-launchd_unix_ipc.o `test -f 'launchd_unix_ipc.c' || echo '$(srcdir)/'`launchd_unix_ipc.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_unix_ipc.Tpo $(DEPDIR)/launchd-launchd_unix_ipc.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_unix_ipc.c' object='launchd-launchd_unix_ipc.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_unix_ipc.o `test -f 'launchd_unix_ipc.c' || echo '$(srcdir)/'`launchd_unix_ipc.c
-
-launchd-launchd_unix_ipc.obj: launchd_unix_ipc.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_unix_ipc.obj -MD -MP -MF $(DEPDIR)/launchd-launchd_unix_ipc.Tpo -c -o launchd-launchd_unix_ipc.obj `if test -f 'launchd_unix_ipc.c'; then $(CYGPATH_W) 'launchd_unix_ipc.c'; else $(CYGPATH_W) '$(srcdir)/launchd_unix_ipc.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_unix_ipc.Tpo $(DEPDIR)/launchd-launchd_unix_ipc.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_unix_ipc.c' object='launchd-launchd_unix_ipc.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_unix_ipc.obj `if test -f 'launchd_unix_ipc.c'; then $(CYGPATH_W) 'launchd_unix_ipc.c'; else $(CYGPATH_W) '$(srcdir)/launchd_unix_ipc.c'; fi`
-
-launchd-protocol_vprocServer.o: protocol_vprocServer.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-protocol_vprocServer.o -MD -MP -MF $(DEPDIR)/launchd-protocol_vprocServer.Tpo -c -o launchd-protocol_vprocServer.o `test -f 'protocol_vprocServer.c' || echo '$(srcdir)/'`protocol_vprocServer.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-protocol_vprocServer.Tpo $(DEPDIR)/launchd-protocol_vprocServer.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='protocol_vprocServer.c' object='launchd-protocol_vprocServer.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-protocol_vprocServer.o `test -f 'protocol_vprocServer.c' || echo '$(srcdir)/'`protocol_vprocServer.c
-
-launchd-protocol_vprocServer.obj: protocol_vprocServer.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-protocol_vprocServer.obj -MD -MP -MF $(DEPDIR)/launchd-protocol_vprocServer.Tpo -c -o launchd-protocol_vprocServer.obj `if test -f 'protocol_vprocServer.c'; then $(CYGPATH_W) 'protocol_vprocServer.c'; else $(CYGPATH_W) '$(srcdir)/protocol_vprocServer.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-protocol_vprocServer.Tpo $(DEPDIR)/launchd-protocol_vprocServer.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='protocol_vprocServer.c' object='launchd-protocol_vprocServer.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-protocol_vprocServer.obj `if test -f 'protocol_vprocServer.c'; then $(CYGPATH_W) 'protocol_vprocServer.c'; else $(CYGPATH_W) '$(srcdir)/protocol_vprocServer.c'; fi`
-
-launchd-notifyServer.o: notifyServer.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-notifyServer.o -MD -MP -MF $(DEPDIR)/launchd-notifyServer.Tpo -c -o launchd-notifyServer.o `test -f 'notifyServer.c' || echo '$(srcdir)/'`notifyServer.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-notifyServer.Tpo $(DEPDIR)/launchd-notifyServer.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='notifyServer.c' object='launchd-notifyServer.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-notifyServer.o `test -f 'notifyServer.c' || echo '$(srcdir)/'`notifyServer.c
-
-launchd-notifyServer.obj: notifyServer.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-notifyServer.obj -MD -MP -MF $(DEPDIR)/launchd-notifyServer.Tpo -c -o launchd-notifyServer.obj `if test -f 'notifyServer.c'; then $(CYGPATH_W) 'notifyServer.c'; else $(CYGPATH_W) '$(srcdir)/notifyServer.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-notifyServer.Tpo $(DEPDIR)/launchd-notifyServer.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='notifyServer.c' object='launchd-notifyServer.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-notifyServer.obj `if test -f 'notifyServer.c'; then $(CYGPATH_W) 'notifyServer.c'; else $(CYGPATH_W) '$(srcdir)/notifyServer.c'; fi`
-
-launchd-launchd_internalUser.o: launchd_internalUser.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_internalUser.o -MD -MP -MF $(DEPDIR)/launchd-launchd_internalUser.Tpo -c -o launchd-launchd_internalUser.o `test -f 'launchd_internalUser.c' || echo '$(srcdir)/'`launchd_internalUser.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_internalUser.Tpo $(DEPDIR)/launchd-launchd_internalUser.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_internalUser.c' object='launchd-launchd_internalUser.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_internalUser.o `test -f 'launchd_internalUser.c' || echo '$(srcdir)/'`launchd_internalUser.c
-
-launchd-launchd_internalUser.obj: launchd_internalUser.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_internalUser.obj -MD -MP -MF $(DEPDIR)/launchd-launchd_internalUser.Tpo -c -o launchd-launchd_internalUser.obj `if test -f 'launchd_internalUser.c'; then $(CYGPATH_W) 'launchd_internalUser.c'; else $(CYGPATH_W) '$(srcdir)/launchd_internalUser.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_internalUser.Tpo $(DEPDIR)/launchd-launchd_internalUser.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_internalUser.c' object='launchd-launchd_internalUser.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_internalUser.obj `if test -f 'launchd_internalUser.c'; then $(CYGPATH_W) 'launchd_internalUser.c'; else $(CYGPATH_W) '$(srcdir)/launchd_internalUser.c'; fi`
-
-launchd-launchd_internalServer.o: launchd_internalServer.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_internalServer.o -MD -MP -MF $(DEPDIR)/launchd-launchd_internalServer.Tpo -c -o launchd-launchd_internalServer.o `test -f 'launchd_internalServer.c' || echo '$(srcdir)/'`launchd_internalServer.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_internalServer.Tpo $(DEPDIR)/launchd-launchd_internalServer.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_internalServer.c' object='launchd-launchd_internalServer.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_internalServer.o `test -f 'launchd_internalServer.c' || echo '$(srcdir)/'`launchd_internalServer.c
-
-launchd-launchd_internalServer.obj: launchd_internalServer.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_internalServer.obj -MD -MP -MF $(DEPDIR)/launchd-launchd_internalServer.Tpo -c -o launchd-launchd_internalServer.obj `if test -f 'launchd_internalServer.c'; then $(CYGPATH_W) 'launchd_internalServer.c'; else $(CYGPATH_W) '$(srcdir)/launchd_internalServer.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_internalServer.Tpo $(DEPDIR)/launchd-launchd_internalServer.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_internalServer.c' object='launchd-launchd_internalServer.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_internalServer.obj `if test -f 'launchd_internalServer.c'; then $(CYGPATH_W) 'launchd_internalServer.c'; else $(CYGPATH_W) '$(srcdir)/launchd_internalServer.c'; fi`
-
-launchd-job_replyUser.o: job_replyUser.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-job_replyUser.o -MD -MP -MF $(DEPDIR)/launchd-job_replyUser.Tpo -c -o launchd-job_replyUser.o `test -f 'job_replyUser.c' || echo '$(srcdir)/'`job_replyUser.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-job_replyUser.Tpo $(DEPDIR)/launchd-job_replyUser.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='job_replyUser.c' object='launchd-job_replyUser.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-job_replyUser.o `test -f 'job_replyUser.c' || echo '$(srcdir)/'`job_replyUser.c
-
-launchd-job_replyUser.obj: job_replyUser.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-job_replyUser.obj -MD -MP -MF $(DEPDIR)/launchd-job_replyUser.Tpo -c -o launchd-job_replyUser.obj `if test -f 'job_replyUser.c'; then $(CYGPATH_W) 'job_replyUser.c'; else $(CYGPATH_W) '$(srcdir)/job_replyUser.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-job_replyUser.Tpo $(DEPDIR)/launchd-job_replyUser.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='job_replyUser.c' object='launchd-job_replyUser.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-job_replyUser.obj `if test -f 'job_replyUser.c'; then $(CYGPATH_W) 'job_replyUser.c'; else $(CYGPATH_W) '$(srcdir)/job_replyUser.c'; fi`
-
-launchd-launchd_runtime.o: launchd_runtime.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_runtime.o -MD -MP -MF $(DEPDIR)/launchd-launchd_runtime.Tpo -c -o launchd-launchd_runtime.o `test -f 'launchd_runtime.c' || echo '$(srcdir)/'`launchd_runtime.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_runtime.Tpo $(DEPDIR)/launchd-launchd_runtime.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_runtime.c' object='launchd-launchd_runtime.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_runtime.o `test -f 'launchd_runtime.c' || echo '$(srcdir)/'`launchd_runtime.c
-
-launchd-launchd_runtime.obj: launchd_runtime.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_runtime.obj -MD -MP -MF $(DEPDIR)/launchd-launchd_runtime.Tpo -c -o launchd-launchd_runtime.obj `if test -f 'launchd_runtime.c'; then $(CYGPATH_W) 'launchd_runtime.c'; else $(CYGPATH_W) '$(srcdir)/launchd_runtime.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_runtime.Tpo $(DEPDIR)/launchd-launchd_runtime.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_runtime.c' object='launchd-launchd_runtime.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_runtime.obj `if test -f 'launchd_runtime.c'; then $(CYGPATH_W) 'launchd_runtime.c'; else $(CYGPATH_W) '$(srcdir)/launchd_runtime.c'; fi`
-
-launchd-launchd_runtime_kill.o: launchd_runtime_kill.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_runtime_kill.o -MD -MP -MF $(DEPDIR)/launchd-launchd_runtime_kill.Tpo -c -o launchd-launchd_runtime_kill.o `test -f 'launchd_runtime_kill.c' || echo '$(srcdir)/'`launchd_runtime_kill.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_runtime_kill.Tpo $(DEPDIR)/launchd-launchd_runtime_kill.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_runtime_kill.c' object='launchd-launchd_runtime_kill.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_runtime_kill.o `test -f 'launchd_runtime_kill.c' || echo '$(srcdir)/'`launchd_runtime_kill.c
-
-launchd-launchd_runtime_kill.obj: launchd_runtime_kill.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-launchd_runtime_kill.obj -MD -MP -MF $(DEPDIR)/launchd-launchd_runtime_kill.Tpo -c -o launchd-launchd_runtime_kill.obj `if test -f 'launchd_runtime_kill.c'; then $(CYGPATH_W) 'launchd_runtime_kill.c'; else $(CYGPATH_W) '$(srcdir)/launchd_runtime_kill.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-launchd_runtime_kill.Tpo $(DEPDIR)/launchd-launchd_runtime_kill.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launchd_runtime_kill.c' object='launchd-launchd_runtime_kill.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_runtime_kill.obj `if test -f 'launchd_runtime_kill.c'; then $(CYGPATH_W) 'launchd_runtime_kill.c'; else $(CYGPATH_W) '$(srcdir)/launchd_runtime_kill.c'; fi`
-
-launchd-mach_excServer.o: mach_excServer.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-mach_excServer.o -MD -MP -MF $(DEPDIR)/launchd-mach_excServer.Tpo -c -o launchd-mach_excServer.o `test -f 'mach_excServer.c' || echo '$(srcdir)/'`mach_excServer.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-mach_excServer.Tpo $(DEPDIR)/launchd-mach_excServer.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mach_excServer.c' object='launchd-mach_excServer.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-mach_excServer.o `test -f 'mach_excServer.c' || echo '$(srcdir)/'`mach_excServer.c
-
-launchd-mach_excServer.obj: mach_excServer.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-mach_excServer.obj -MD -MP -MF $(DEPDIR)/launchd-mach_excServer.Tpo -c -o launchd-mach_excServer.obj `if test -f 'mach_excServer.c'; then $(CYGPATH_W) 'mach_excServer.c'; else $(CYGPATH_W) '$(srcdir)/mach_excServer.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/launchd-mach_excServer.Tpo $(DEPDIR)/launchd-mach_excServer.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mach_excServer.c' object='launchd-mach_excServer.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-mach_excServer.obj `if test -f 'mach_excServer.c'; then $(CYGPATH_W) 'mach_excServer.c'; else $(CYGPATH_W) '$(srcdir)/mach_excServer.c'; fi`
-install-man1: $(man1_MANS) $(man_MANS)
- @$(NORMAL_INSTALL)
- test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
- @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
- l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
- for i in $$l2; do \
- case "$$i" in \
- *.1*) list="$$list $$i" ;; \
- esac; \
- done; \
- for i in $$list; do \
- if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
- else file=$$i; fi; \
- ext=`echo $$i | sed -e 's/^.*\\.//'`; \
- case "$$ext" in \
- 1*) ;; \
- *) ext='1' ;; \
- esac; \
- inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
- inst=`echo $$inst | sed -e 's/^.*\///'`; \
- inst=`echo $$inst | sed '$(transform)'`.$$ext; \
- echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
- $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
- done
-uninstall-man1:
- @$(NORMAL_UNINSTALL)
- @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
- l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
- for i in $$l2; do \
- case "$$i" in \
- *.1*) list="$$list $$i" ;; \
- esac; \
- done; \
- for i in $$list; do \
- ext=`echo $$i | sed -e 's/^.*\\.//'`; \
- case "$$ext" in \
- 1*) ;; \
- *) ext='1' ;; \
- esac; \
- inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
- inst=`echo $$inst | sed -e 's/^.*\///'`; \
- inst=`echo $$inst | sed '$(transform)'`.$$ext; \
- echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
- rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
- done
-install-man5: $(man5_MANS) $(man_MANS)
- @$(NORMAL_INSTALL)
- test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)"
- @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
- l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
- for i in $$l2; do \
- case "$$i" in \
- *.5*) list="$$list $$i" ;; \
- esac; \
- done; \
- for i in $$list; do \
- if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
- else file=$$i; fi; \
- ext=`echo $$i | sed -e 's/^.*\\.//'`; \
- case "$$ext" in \
- 5*) ;; \
- *) ext='5' ;; \
- esac; \
- inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
- inst=`echo $$inst | sed -e 's/^.*\///'`; \
- inst=`echo $$inst | sed '$(transform)'`.$$ext; \
- echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
- $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \
- done
-uninstall-man5:
- @$(NORMAL_UNINSTALL)
- @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
- l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
- for i in $$l2; do \
- case "$$i" in \
- *.5*) list="$$list $$i" ;; \
- esac; \
- done; \
- for i in $$list; do \
- ext=`echo $$i | sed -e 's/^.*\\.//'`; \
- case "$$ext" in \
- 5*) ;; \
- *) ext='5' ;; \
- esac; \
- inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
- inst=`echo $$inst | sed -e 's/^.*\///'`; \
- inst=`echo $$inst | sed '$(transform)'`.$$ext; \
- echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \
- rm -f "$(DESTDIR)$(man5dir)/$$inst"; \
- done
-install-man8: $(man8_MANS) $(man_MANS)
- @$(NORMAL_INSTALL)
- test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)"
- @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
- l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
- for i in $$l2; do \
- case "$$i" in \
- *.8*) list="$$list $$i" ;; \
- esac; \
- done; \
- for i in $$list; do \
- if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
- else file=$$i; fi; \
- ext=`echo $$i | sed -e 's/^.*\\.//'`; \
- case "$$ext" in \
- 8*) ;; \
- *) ext='8' ;; \
- esac; \
- inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
- inst=`echo $$inst | sed -e 's/^.*\///'`; \
- inst=`echo $$inst | sed '$(transform)'`.$$ext; \
- echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
- $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
- done
-uninstall-man8:
- @$(NORMAL_UNINSTALL)
- @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
- l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
- for i in $$l2; do \
- case "$$i" in \
- *.8*) list="$$list $$i" ;; \
- esac; \
- done; \
- for i in $$list; do \
- ext=`echo $$i | sed -e 's/^.*\\.//'`; \
- case "$$ext" in \
- 8*) ;; \
- *) ext='8' ;; \
- esac; \
- inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
- inst=`echo $$inst | sed -e 's/^.*\///'`; \
- inst=`echo $$inst | sed '$(transform)'`.$$ext; \
- echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
- rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
- done
-install-sysconfDATA: $(sysconf_DATA)
- @$(NORMAL_INSTALL)
- test -z "$(sysconfdir)" || $(MKDIR_P) "$(DESTDIR)$(sysconfdir)"
- @list='$(sysconf_DATA)'; for p in $$list; do \
- if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
- f=$(am__strip_dir) \
- echo " $(sysconfDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(sysconfdir)/$$f'"; \
- $(sysconfDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(sysconfdir)/$$f"; \
- done
-
-uninstall-sysconfDATA:
- @$(NORMAL_UNINSTALL)
- @list='$(sysconf_DATA)'; for p in $$list; do \
- f=$(am__strip_dir) \
- echo " rm -f '$(DESTDIR)$(sysconfdir)/$$f'"; \
- rm -f "$(DESTDIR)$(sysconfdir)/$$f"; \
- done
-
-ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
- list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
- unique=`for i in $$list; do \
- if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
- done | \
- $(AWK) ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- mkid -fID $$unique
-tags: TAGS
-
-TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
- $(TAGS_FILES) $(LISP)
- tags=; \
- here=`pwd`; \
- list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
- unique=`for i in $$list; do \
- if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
- done | \
- $(AWK) ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
- test -n "$$unique" || unique=$$empty_fix; \
- $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
- $$tags $$unique; \
- fi
-ctags: CTAGS
-CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
- $(TAGS_FILES) $(LISP)
- tags=; \
- here=`pwd`; \
- list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
- unique=`for i in $$list; do \
- if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
- done | \
- $(AWK) ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- test -z "$(CTAGS_ARGS)$$tags$$unique" \
- || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
- $$tags $$unique
-
-GTAGS:
- here=`$(am__cd) $(top_builddir) && pwd` \
- && cd $(top_srcdir) \
- && gtags -i $(GTAGS_ARGS) $$here
-
-distclean-tags:
- -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-distdir: $(DISTFILES)
- @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
- topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
- list='$(DISTFILES)'; \
- dist_files=`for file in $$list; do echo $$file; done | \
- sed -e "s|^$$srcdirstrip/||;t" \
- -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
- case $$dist_files in \
- */*) $(MKDIR_P) `echo "$$dist_files" | \
- sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
- sort -u` ;; \
- esac; \
- for file in $$dist_files; do \
- if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
- if test -d $$d/$$file; then \
- dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
- if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
- cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
- fi; \
- cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
- else \
- test -f $(distdir)/$$file \
- || cp -p $$d/$$file $(distdir)/$$file \
- || exit 1; \
- fi; \
- done
-check-am: all-am
-check: check-am
-all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(MANS) $(DATA) config.h
-installdirs:
- for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(sysconfdir)"; do \
- test -z "$$dir" || $(MKDIR_P) "$$dir"; \
- done
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
- @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
- $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
- install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
- `test -z '$(STRIP)' || \
- echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
-mostlyclean-generic:
-
-clean-generic:
- -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
-
-distclean-generic:
- -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-
-maintainer-clean-generic:
- @echo "This command is intended for maintainers to use"
- @echo "it deletes files that may require special tools to rebuild."
-clean: clean-am
-
-clean-am: clean-binPROGRAMS clean-generic clean-libexecPROGRAMS \
- clean-noinstLIBRARIES clean-sbinPROGRAMS mostlyclean-am
-
-distclean: distclean-am
- -rm -rf ./$(DEPDIR)
- -rm -f Makefile
-distclean-am: clean-am distclean-compile distclean-generic \
- distclean-hdr distclean-tags
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-info: info-am
-
-info-am:
-
-install-data-am: install-man
- @$(NORMAL_INSTALL)
- $(MAKE) $(AM_MAKEFLAGS) install-data-hook
-
-install-dvi: install-dvi-am
-
-install-exec-am: install-binPROGRAMS install-libexecPROGRAMS \
- install-sbinPROGRAMS install-sysconfDATA
-
-install-html: install-html-am
-
-install-info: install-info-am
-
-install-man: install-man1 install-man5 install-man8
-
-install-pdf: install-pdf-am
-
-install-ps: install-ps-am
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
- -rm -rf ./$(DEPDIR)
- -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-compile mostlyclean-generic
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am: uninstall-binPROGRAMS uninstall-libexecPROGRAMS \
- uninstall-man uninstall-sbinPROGRAMS uninstall-sysconfDATA
-
-uninstall-man: uninstall-man1 uninstall-man5 uninstall-man8
-
-.MAKE: install-am install-data-am install-strip
-
-.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
- clean-generic clean-libexecPROGRAMS clean-noinstLIBRARIES \
- clean-sbinPROGRAMS ctags distclean distclean-compile \
- distclean-generic distclean-hdr distclean-tags distdir dvi \
- dvi-am html html-am info info-am install install-am \
- install-binPROGRAMS install-data install-data-am \
- install-data-hook install-dvi install-dvi-am install-exec \
- install-exec-am install-html install-html-am install-info \
- install-info-am install-libexecPROGRAMS install-man \
- install-man1 install-man5 install-man8 install-pdf \
- install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \
- install-strip install-sysconfDATA installcheck installcheck-am \
- installdirs maintainer-clean maintainer-clean-generic \
- mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \
- ps ps-am tags uninstall uninstall-am uninstall-binPROGRAMS \
- uninstall-libexecPROGRAMS uninstall-man uninstall-man1 \
- uninstall-man5 uninstall-man8 uninstall-sbinPROGRAMS \
- uninstall-sysconfDATA
-
-
-protocol_vproc.h protocol_vprocServer.c protocol_vprocUser.c protocol_vprocServer.h: $(srcdir)/protocol_job.defs
- mig $(MIGFLAGS) -sheader protocol_vprocServer.h $(srcdir)/protocol_job.defs
-
-@LIBS_ONLY_TRUE@$(srcdir)/libvproc.c:: protocol_vproc.h
-
-@LIBS_ONLY_TRUE@$(srcdir)/protocol_vprocUser.c:: protocol_vproc.h
-
-@LIBS_ONLY_TRUE@__version.c:
-@LIBS_ONLY_TRUE@ /Developer/Makefiles/bin/version.pl launchd_libs > $@
-
-@LIBS_ONLY_TRUE@install-data-hook:
-@LIBS_ONLY_TRUE@ mkdir -p $(DESTDIR)/usr/local/lib/system
-@LIBS_ONLY_TRUE@ cp liblaunch.a $(DESTDIR)/usr/local/lib/system
-@LIBS_ONLY_TRUE@ cp liblaunch.a $(DESTDIR)/usr/local/lib/system/liblaunch_debug.a
-@LIBS_ONLY_TRUE@ cp liblaunch_profile.a $(DESTDIR)/usr/local/lib/system/liblaunch_profile.a
-
-@LIBS_ONLY_FALSE@launchd_runtime.c:: notifyServer.h launchd_internal.h mach_excServer.h
-@LIBS_ONLY_FALSE@launchd_core_logic.c:: protocol_vproc.h job_reply.h protocol_vprocServer.h
-
-@LIBS_ONLY_FALSE@notifyServer.c notifyServer.h: /usr/include/mach/notify.defs
-@LIBS_ONLY_FALSE@ mig $(MIGFLAGS) -header /dev/null -user /dev/null -sheader notifyServer.h /usr/include/mach/notify.defs
-
-@LIBS_ONLY_FALSE@mach_excServer.c mach_excServer.h: /usr/include/mach/mach_exc.defs
-@LIBS_ONLY_FALSE@ mig $(MIGFLAGS) -header /dev/null -user /dev/null -sheader mach_excServer.h /usr/include/mach/mach_exc.defs
-
-@LIBS_ONLY_FALSE@job_replyUser.c job_reply.h: $(srcdir)/protocol_job_reply.defs
-@LIBS_ONLY_FALSE@ mig $(MIGFLAGS) -sheader /dev/null -server /dev/null $(srcdir)/protocol_job_reply.defs
-
-@LIBS_ONLY_FALSE@launchd_internal.h launchd_internalServer.c launchd_internalUser.c launchd_internalServer.h: $(srcdir)/launchd_internal.defs
-@LIBS_ONLY_FALSE@ mig $(MIGFLAGS) -sheader launchd_internalServer.h $(srcdir)/launchd_internal.defs
-
-@LIBS_ONLY_FALSE@install-data-hook:
-@LIBS_ONLY_FALSE@ mkdir -p $(DESTDIR)/usr/libexec
-@LIBS_ONLY_FALSE@ mkdir -p $(DESTDIR)/usr/include/servers
-@LIBS_ONLY_FALSE@ mkdir -p $(DESTDIR)/usr/local/include
-@LIBS_ONLY_FALSE@ mkdir -p $(DESTDIR)/$(sysconfdir)/mach_init.d
-@LIBS_ONLY_FALSE@ mkdir -p $(DESTDIR)/$(sysconfdir)/mach_init_per_user.d
-@LIBS_ONLY_FALSE@ mkdir -p $(DESTDIR)/$(sysconfdir)/mach_init_per_login_session.d
-@LIBS_ONLY_FALSE@ mkdir -p $(DESTDIR)/Library/LaunchDaemons
-@LIBS_ONLY_FALSE@ mkdir -p $(DESTDIR)/Library/LaunchAgents
-@LIBS_ONLY_FALSE@ mkdir -p $(DESTDIR)/System/Library/LaunchAgents
-@LIBS_ONLY_FALSE@ mkdir -p $(DESTDIR)/System/Library/LaunchDaemons
-@LIBS_ONLY_FALSE@ cp $(srcdir)/liblaunch_public.h $(DESTDIR)/usr/include/launch.h
-@LIBS_ONLY_FALSE@ cp $(srcdir)/libvproc_public.h $(DESTDIR)/usr/include/vproc.h
-@LIBS_ONLY_FALSE@ cp $(srcdir)/libbootstrap_public.h $(DESTDIR)/usr/include/servers/bootstrap.h
-@LIBS_ONLY_FALSE@ cp $(srcdir)/libbootstrap_public.h $(DESTDIR)/usr/include/servers/bootstrap_defs.h
-@LIBS_ONLY_FALSE@ cp $(srcdir)/libbootstrap_private.h $(DESTDIR)/usr/local/include/bootstrap_priv.h
-@LIBS_ONLY_FALSE@ cp $(srcdir)/liblaunch_private.h $(DESTDIR)/usr/local/include/launch_priv.h
-@LIBS_ONLY_FALSE@ cp $(srcdir)/libvproc_private.h $(DESTDIR)/usr/local/include/vproc_priv.h
-@LIBS_ONLY_FALSE@ cp $(srcdir)/reboot2.h $(DESTDIR)/usr/local/include/reboot2.h
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@ cp $(srcdir)/StartupItemContext $(DESTDIR)/usr/libexec
-@DO_EMBEDDED_MAGIC_FALSE@@LIBS_ONLY_FALSE@ cp $(srcdir)/com.apple.SystemStarter.plist $(DESTDIR)/System/Library/LaunchDaemons
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
}
/**
- * startupItemListGetMatches returns an array of items which contain the string aService in the key aKey
+ * startupItemListCopyMatches returns an array of items which contain the string aService in the key aKey
**/
-static CFMutableArrayRef startupItemListGetMatches(CFArrayRef anItemList, CFStringRef aKey, CFStringRef aService)
+static CFMutableArrayRef startupItemListCopyMatches(CFArrayRef anItemList, CFStringRef aKey, CFStringRef aService)
{
CFMutableArrayRef aResult = NULL;
}
CFDictionaryReplaceValue(aConfig, type, aNewList);
+ CFRelease(aNewList);
}
if (type == kUsesKey)
return;
return aResult;
}
-static bool StartupItemSecurityCheck(const char *aPath)
+bool StartupItemSecurityCheck(const char *aPath)
{
static struct timeval boot_time;
struct stat aStatBuf;
while ((aState = NSGetNextSearchPathEnumeration(aState, aPath))) {
DIR *aDirectory;
- strcpy(aPath + strlen(aPath), kStartupItemsPath);
+ strlcat(aPath, kStartupItemsPath, sizeof(aPath));
++aDomainIndex;
/* 5485016
*
* Just in case...
*/
- mkdir(aPath, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH);
+ mkdir(aPath, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
if (!StartupItemSecurityCheck(aPath))
continue;
CFMutableDictionaryRef StartupItemListGetProvider(CFArrayRef anItemList, CFStringRef aService)
{
CFMutableDictionaryRef aResult = NULL;
- CFMutableArrayRef aList = startupItemListGetMatches(anItemList, kProvidesKey, aService);
+ CFMutableArrayRef aList = startupItemListCopyMatches(anItemList, kProvidesKey, aService);
if (aList && CFArrayGetCount(aList) > 0)
aResult = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aList, 0);
+ if (aList) CFRelease(aList);
+
return aResult;
}
for (anItemIndex = 0; anItemIndex < anItemCount; anItemIndex++) {
CFStringRef anItem = CFArrayGetValueAtIndex(anItemList, anItemIndex);
- CFArrayRef aMatchesList = startupItemListGetMatches(aWaitingList, aKey, anItem);
+ CFArrayRef aMatchesList = startupItemListCopyMatches(aWaitingList, aKey, anItem);
if (aMatchesList) {
aCount = aCount + CFArrayGetCount(aMatchesList);
for (anAntecedentIndex = 0; anAntecedentIndex < anAntecedentCount; ++anAntecedentIndex) {
CFStringRef anAntecedent = CFArrayGetValueAtIndex(anAntecedentList, anAntecedentIndex);
CFStringRef aKey = (anAction == kActionStart) ? kProvidesKey : kUsesKey;
- CFArrayRef aMatchesList = startupItemListGetMatches(aWaitingList, aKey, anAntecedent);
+ CFArrayRef aMatchesList = startupItemListCopyMatches(aWaitingList, aKey, anAntecedent);
if (aMatchesList) {
CFIndex aMatchesListCount = CFArrayGetCount(aMatchesList);
* might provide that service.
*/
else {
- CFArrayRef aMatchesList = startupItemListGetMatches(aWaitingList, kProvidesKey, aProvides);
+ CFArrayRef aMatchesList = startupItemListCopyMatches(aWaitingList, kProvidesKey, aProvides);
if (aMatchesList) {
CFIndex aMatchesListCount = CFArrayGetCount(aMatchesList);
CFIndex aMatchesListIndex;
anError = 0;
} else {
CFStringRef aBundlePathString = CFDictionaryGetValue(anItem, kBundlePathKey);
- size_t aBundlePathCLength =
- CFStringGetMaximumSizeForEncoding(CFStringGetLength(aBundlePathString), kCFStringEncodingUTF8) + 1;
- char *aBundlePath = (char *)malloc(aBundlePathCLength);
- char anExecutable[PATH_MAX] = "";
+ char aBundlePath[PATH_MAX];
+ char anExecutable[PATH_MAX];
+ char *tmp;
- if (!aBundlePath) {
- syslog(LOG_EMERG, "malloc() failed; out of memory while running item %s", aBundlePathString);
- return (anError);
- }
- if (!CFStringGetCString(aBundlePathString, aBundlePath, aBundlePathCLength, kCFStringEncodingUTF8)) {
+ if (!CFStringGetCString(aBundlePathString, aBundlePath, sizeof(aBundlePath), kCFStringEncodingUTF8)) {
CF_syslog(LOG_EMERG, CFSTR("Internal error while running item %@"), aBundlePathString);
return (anError);
}
/* Compute path to excecutable */
- {
- char *tmp;
- strncpy(anExecutable, aBundlePath, sizeof(anExecutable)); /* .../foo */
- tmp = rindex(anExecutable, '/'); /* /foo */
- strncat(anExecutable, tmp, strlen(tmp)); /* .../foo/foo */
- }
-
- free(aBundlePath);
+ tmp = rindex(aBundlePath, '/');
+ snprintf(anExecutable, sizeof(anExecutable), "%s%s", aBundlePath, tmp);
/**
* Run the bundle
void StartupItemExit (CFMutableDictionaryRef aStatusDict, CFMutableDictionaryRef anItem, Boolean aSuccess);
void StartupItemSetStatus(CFMutableDictionaryRef aStatusDict, CFMutableDictionaryRef anItem, CFStringRef aServiceName, Boolean aSuccess, Boolean aReplaceFlag);
+/*
+ * Check whether file was created before boot and has proper permissions to run.
+ */
+bool StartupItemSecurityCheck(const char *aPath);
+
#endif /* _StartupItems_H_ */
.Op Fl gvxdDqn
.Op Ar action Op Ar service
.Sh DESCRIPTION
-The
+The
+.Nm
+utility is deprecated. System services should instead be described by a
+.Xr launchd.plist 5 .
+See
+.Xr launchd 8
+for more details.
+The
+.Nm launchd
+utility is available on Mac OS X 10.4 and later.
+.Pp
+In earlier versions of Mac OS X, the
.Nm
-utility may be used to start, stop, and restart the system services which
+utility is used to start, stop, and restart the system services which
are described in the
.Pa /Library/StartupItems/
and
During boot
.Nm
is invoked by
-.Nm rc
-(see rc(8)) and is responsible for
+.Xr launchd 8
+and is responsible for
starting all startup items in an order that satisfies each item's
requirements.
.Sh ACTIONS
.Nm
examines the exit status of the startup item scripts to determine the success or failure of the services provided by that script.
.Pp
-In Darwin it is preferable to create custom startup items than to modify
-.Nm rc ,
-and at some point
-.Nm
-may entirely encompass the role of
-.Nm rc .
.Sh FILES
.Bl -tag -width -/System/Library/StartupItems -compact
.It Pa /Library/StartupItems/
.Sh SEE ALSO
.\" List links in ascending order by section, alphabetically within a section.
.\" Please do not reference files that do not exist without filing a bug report
-.Xr ConsoleMessage 8
-.Pp
+.Xr ConsoleMessage 8 ,
+.Xr launchd 8 ,
+.Xr launchd.plist 5 ,
.Xr rc 8
.\" .Sh BUGS \" Document known, unremedied bugs
.Sh HISTORY
The
.Nm
-utility appeared in Darwin 1.0
-.Pp
-.Nm
+utility appeared in Darwin 1.0 and
was extended in Darwin 6.0 to support partial startup and interprocess communication.
+.Nm
+was deprecated by
+.Xr launchd 8
+in Darwin 8.0.
#include <syslog.h>
#include <assert.h>
#include <CoreFoundation/CoreFoundation.h>
+#include <DiskArbitration/DiskArbitration.h>
+#include <DiskArbitration/DiskArbitrationPrivate.h>
#include <NSSystemDirectories.h>
#include "IPC.h"
#include "StartupItems.h"
static void usage(void) __attribute__((noreturn));
static int system_starter(Action anAction, const char *aService);
-static void displayErrorMessages(StartupContext aStartupContext);
+static void displayErrorMessages(StartupContext aStartupContext, Action anAction);
static pid_t fwexec(const char *cmd, ...) __attribute__((sentinel));
+static void autodiskmount(void);
static void dummy_sig(int signo __attribute__((unused)))
{
}
mach_timespec_t w = { 600, 0 };
kern_return_t kr;
- struct stat sb;
/*
* Too many old StartupItems had implicit dependancies on "Network" via
}
fwexec("/usr/sbin/ipconfig", "waitall", NULL);
- fwexec("/sbin/autodiskmount", "-va", NULL);
+ autodiskmount(); /* wait for Disk Arbitration to report idle */
system_starter(kActionStart, NULL);
- if (stat("/etc/rc.local", &sb) != -1) {
+ if (StartupItemSecurityCheck("/etc/rc.local")) {
fwexec(_PATH_BSHELL, "/etc/rc.local", NULL);
}
assert(r != -1);
assert(kev.filter == EVFILT_SIGNAL && kev.ident == SIGTERM);
- if (stat("/etc/rc.shutdown.local", &sb) != -1) {
+ if (StartupItemSecurityCheck("/etc/rc.shutdown.local")) {
fwexec(_PATH_BSHELL, "/etc/rc.shutdown.local", NULL);
}
* print out any error messages to the log regarding non starting StartupItems
*/
void
-displayErrorMessages(StartupContext aStartupContext)
+displayErrorMessages(StartupContext aStartupContext, Action anAction)
{
if (aStartupContext->aFailedList && CFArrayGetCount(aStartupContext->aFailedList) > 0) {
CFIndex anItemCount = CFArrayGetCount(aStartupContext->aFailedList);
CFIndex anItemIndex;
- syslog(LOG_WARNING, "The following StartupItems failed to properly start:");
+ syslog(LOG_WARNING, "The following StartupItems failed to %s properly:", (anAction == kActionStart) ? "start" : "stop");
for (anItemIndex = 0; anItemIndex < anItemCount; anItemIndex++) {
CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aStartupContext->aFailedList, anItemIndex);
/**
* Good-bye.
**/
- displayErrorMessages(aStartupContext);
+ displayErrorMessages(aStartupContext, anAction);
/* clean up */
if (aStartupContext->aStatusDict)
return -1;
}
+
+static void
+autodiskmount_idle(void* context __attribute__((unused)))
+{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+}
+
+static void
+autodiskmount(void)
+{
+ DASessionRef session = DASessionCreate(NULL);
+ if (session) {
+ DASessionScheduleWithRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ DARegisterIdleCallback(session, autodiskmount_idle, NULL);
+ CFRunLoopRun();
+ CFRelease(session);
+ }
+}
typedef name_t *name_array_t;
typedef int bootstrap_status_t;
typedef bootstrap_status_t *bootstrap_status_array_t;
+typedef unsigned int bootstrap_property_t;
+typedef bootstrap_property_t * bootstrap_property_array_t;
typedef boolean_t *bool_array_t;
#define BOOTSTRAP_MAX_LOOKUP_COUNT 20
-#define BOOTSTRAP_SUCCESS 0
+#define BOOTSTRAP_SUCCESS 0
#define BOOTSTRAP_NOT_PRIVILEGED 1100
#define BOOTSTRAP_NAME_IN_USE 1101
#define BOOTSTRAP_UNKNOWN_SERVICE 1102
#define BOOTSTRAP_SERVICE_ACTIVE 1103
-#define BOOTSTRAP_BAD_COUNT 1104
-#define BOOTSTRAP_NO_MEMORY 1105
+#define BOOTSTRAP_BAD_COUNT 1104
+#define BOOTSTRAP_NO_MEMORY 1105
+#define BOOTSTRAP_NO_CHILDREN 1106
#define BOOTSTRAP_STATUS_INACTIVE 0
#define BOOTSTRAP_STATUS_ACTIVE 1
*
* This API is deprecated. Old scenarios and recommendations:
*
- * 1) If the code was registering a well known name, please switch to launchd.
+ * 1) Code that used to call bootstrap_check_in() and then bootstrap_register()
+ * can now always call bootstrap_check_in().
*
- * 2) If the code was registering a dynamically generated string and passing
+ * 2) If the code was registering a well known name, please switch to launchd.
+ *
+ * 3) If the code was registering a dynamically generated string and passing
* the string to other applications, please rewrite the code to send a Mach
* send-right directly.
*
- * 3) If the launchd job maintained an optional Mach service, please reserve
+ * 4) If the launchd job maintained an optional Mach service, please reserve
* the name with launchd and control the presense of the service through
* ownership of the Mach receive right like so.
*
* Returns BOOTSTRAP_NAME_IN_USE, if service has already been
* register or checked-in.
*/
-kern_return_t bootstrap_register(
- mach_port_t bp,
- name_t service_name,
- mach_port_t sp)
- AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
+AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5
+kern_return_t
+bootstrap_register(mach_port_t bp, name_t service_name, mach_port_t sp);
/*
* bootstrap_create_service()
*
- * Creates a service named "service_name" and returns send rights to that
+ * Creates a service named "service_name" and returns a send right to that
* port in "service_port." The port may later be checked in as if this
* port were configured in the bootstrap configuration file.
*
+ * This API is deprecated. Please call bootstrap_check_in() instead.
+ *
* Errors: Returns appropriate kernel errors on rpc failure.
* Returns BOOTSTRAP_SERVICE_ACTIVE, if service already exists.
*/
-kern_return_t bootstrap_create_service(
- mach_port_t bp,
- name_t service_name,
- mach_port_t *sp);
+#ifdef AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6
+AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6
+#endif
+kern_return_t
+bootstrap_create_service(mach_port_t bp, name_t service_name, mach_port_t *sp);
/*
* bootstrap_check_in()
*/
kern_return_t bootstrap_check_in(
mach_port_t bp,
- name_t service_name,
+ const name_t service_name,
mach_port_t *sp);
/*
*/
kern_return_t bootstrap_look_up(
mach_port_t bp,
- name_t service_name,
+ const name_t service_name,
mach_port_t *sp);
/*
#pragma GCC visibility push(default)
-#define BOOTSTRAP_PER_PID_SERVICE 0x1
-#define BOOTSTRAP_ALLOW_LOOKUP 0x2
-#define BOOTSTRAP_DENY_JOB_CREATION 0x4
+#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_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. */
kern_return_t bootstrap_register2(mach_port_t bp, name_t service_name, mach_port_t sp, uint64_t flags);
-kern_return_t bootstrap_look_up2(mach_port_t bp, 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);
+
+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_look_up_per_user(mach_port_t bp, name_t service_name, uid_t target_user, mach_port_t *sp);
+kern_return_t bootstrap_look_up_per_user(mach_port_t bp, const name_t service_name, uid_t target_user, mach_port_t *sp);
-kern_return_t bootstrap_set_policy(mach_port_t bp, pid_t target_pid, uint64_t flags, const char *target_service);
+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);
#pragma GCC visibility pop
#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
#endif /* __CONFIG_H__ */
+++ /dev/null
-/* src/config.h.in. Generated from configure.ac by autoheader. */
-
-/* Define to 1 if the `closedir' function returns void instead of `int'. */
-#undef CLOSEDIR_VOID
-
-/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
- systems. This function is required for `alloca.c' support on those systems.
- */
-#undef CRAY_STACKSEG_END
-
-/* Define to 1 if using `alloca.c'. */
-#undef C_ALLOCA
-
-/* Define to 1 if you have the `alarm' function. */
-#undef HAVE_ALARM
-
-/* Define to 1 if you have `alloca', as a function or macro. */
-#undef HAVE_ALLOCA
-
-/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
- */
-#undef HAVE_ALLOCA_H
-
-/* Define to 1 if you have the `atexit' function. */
-#undef HAVE_ATEXIT
-
-/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
- */
-#undef HAVE_DIRENT_H
-
-/* Define to 1 if you have the `dup2' function. */
-#undef HAVE_DUP2
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#undef HAVE_FCNTL_H
-
-/* Define to 1 if you have the `fork' function. */
-#undef HAVE_FORK
-
-/* Define to 1 if you have the `gethostname' function. */
-#undef HAVE_GETHOSTNAME
-
-/* Define to 1 if you have the `gettimeofday' function. */
-#undef HAVE_GETTIMEOFDAY
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#undef HAVE_INTTYPES_H
-
-/* Define to 1 if you have the <limits.h> header file. */
-#undef HAVE_LIMITS_H
-
-/* Define to 1 if `lstat' has the bug that it succeeds when given the
- zero-length file name argument. */
-#undef HAVE_LSTAT_EMPTY_STRING_BUG
-
-/* Define to 1 if you have the <mach/mach.h> header file. */
-#undef HAVE_MACH_MACH_H
-
-/* Define to 1 if you have the `malloc' function. */
-#undef HAVE_MALLOC
-
-/* Define to 1 if you have the `memmove' function. */
-#undef HAVE_MEMMOVE
-
-/* Define to 1 if you have the <memory.h> header file. */
-#undef HAVE_MEMORY_H
-
-/* Define to 1 if you have the `memset' function. */
-#undef HAVE_MEMSET
-
-/* Define to 1 if you have the `mkdir' function. */
-#undef HAVE_MKDIR
-
-/* Define to 1 if you have the `mmap' function. */
-#undef HAVE_MMAP
-
-/* Define to 1 if you have the `munmap' function. */
-#undef HAVE_MUNMAP
-
-/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
-#undef HAVE_NDIR_H
-
-/* Define to 1 if you have the <netdb.h> header file. */
-#undef HAVE_NETDB_H
-
-/* Define to 1 if you have the <netinet/in.h> header file. */
-#undef HAVE_NETINET_IN_H
-
-/* Define to 1 if you have the <paths.h> header file. */
-#undef HAVE_PATHS_H
-
-/* Define to 1 if you have the quarantine library */
-#undef HAVE_QUARANTINE
-
-/* Define to 1 if you have the `realloc' function. */
-#undef HAVE_REALLOC
-
-/* Define to 1 if you have the `rmdir' function. */
-#undef HAVE_RMDIR
-
-/* Define to 1 if you have the sandbox library */
-#undef HAVE_SANDBOX
-
-/* Define to 1 if you have the Security framework */
-#undef HAVE_SECURITY
-
-/* Define to 1 if you have the `select' function. */
-#undef HAVE_SELECT
-
-/* Define to 1 if you have the `setenv' function. */
-#undef HAVE_SETENV
-
-/* Define to 1 if you have the `socket' function. */
-#undef HAVE_SOCKET
-
-/* Define to 1 if `stat' has the bug that it succeeds when given the
- zero-length file name argument. */
-#undef HAVE_STAT_EMPTY_STRING_BUG
-
-/* Define to 1 if stdbool.h conforms to C99. */
-#undef HAVE_STDBOOL_H
-
-/* Define to 1 if you have the <stddef.h> header file. */
-#undef HAVE_STDDEF_H
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#undef HAVE_STDINT_H
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#undef HAVE_STDLIB_H
-
-/* Define to 1 if you have the `strcasecmp' function. */
-#undef HAVE_STRCASECMP
-
-/* Define to 1 if you have the `strchr' function. */
-#undef HAVE_STRCHR
-
-/* Define to 1 if you have the `strdup' function. */
-#undef HAVE_STRDUP
-
-/* Define to 1 if you have the `strerror' function. */
-#undef HAVE_STRERROR
-
-/* Define to 1 if you have the <strings.h> header file. */
-#undef HAVE_STRINGS_H
-
-/* Define to 1 if you have the <string.h> header file. */
-#undef HAVE_STRING_H
-
-/* Define to 1 if you have the `strrchr' function. */
-#undef HAVE_STRRCHR
-
-/* Define to 1 if you have the `strstr' function. */
-#undef HAVE_STRSTR
-
-/* Define to 1 if you have the `strtol' function. */
-#undef HAVE_STRTOL
-
-/* Define to 1 if you have the <syslog.h> header file. */
-#undef HAVE_SYSLOG_H
-
-/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
- */
-#undef HAVE_SYS_DIR_H
-
-/* Define to 1 if you have the <sys/ioctl.h> header file. */
-#undef HAVE_SYS_IOCTL_H
-
-/* Define to 1 if you have the <sys/mount.h> header file. */
-#undef HAVE_SYS_MOUNT_H
-
-/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
- */
-#undef HAVE_SYS_NDIR_H
-
-/* Define to 1 if you have the <sys/param.h> header file. */
-#undef HAVE_SYS_PARAM_H
-
-/* Define to 1 if you have the <sys/select.h> header file. */
-#undef HAVE_SYS_SELECT_H
-
-/* Define to 1 if you have the <sys/socket.h> header file. */
-#undef HAVE_SYS_SOCKET_H
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#undef HAVE_SYS_STAT_H
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#undef HAVE_SYS_TIME_H
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#undef HAVE_SYS_TYPES_H
-
-/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
-#undef HAVE_SYS_WAIT_H
-
-/* Define to 1 if you have the <termios.h> header file. */
-#undef HAVE_TERMIOS_H
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#undef HAVE_UNISTD_H
-
-/* Define to 1 if you have the `vfork' function. */
-#undef HAVE_VFORK
-
-/* Define to 1 if you have the <vfork.h> header file. */
-#undef HAVE_VFORK_H
-
-/* Define to 1 if `fork' works. */
-#undef HAVE_WORKING_FORK
-
-/* Define to 1 if `vfork' works. */
-#undef HAVE_WORKING_VFORK
-
-/* Define to 1 if the system has the type `_Bool'. */
-#undef HAVE__BOOL
-
-/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
- slash. */
-#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
-
-/* Define to 1 if your C compiler doesn't accept -c and -o together. */
-#undef NO_MINUS_C_MINUS_O
-
-/* Name of package */
-#undef PACKAGE
-
-/* Define to the address where bug reports for this package should be sent. */
-#undef PACKAGE_BUGREPORT
-
-/* Define to the full name of this package. */
-#undef PACKAGE_NAME
-
-/* Define to the full name and version of this package. */
-#undef PACKAGE_STRING
-
-/* Define to the one symbol short name of this package. */
-#undef PACKAGE_TARNAME
-
-/* Define to the version of this package. */
-#undef PACKAGE_VERSION
-
-/* Define as the return type of signal handlers (`int' or `void'). */
-#undef RETSIGTYPE
-
-/* Define to the type of arg 1 for `select'. */
-#undef SELECT_TYPE_ARG1
-
-/* Define to the type of args 2, 3 and 4 for `select'. */
-#undef SELECT_TYPE_ARG234
-
-/* Define to the type of arg 5 for `select'. */
-#undef SELECT_TYPE_ARG5
-
-/* If using the C implementation of alloca, define if you know the
- direction of stack growth for your system; otherwise it will be
- automatically deduced at runtime.
- STACK_DIRECTION > 0 => grows toward higher addresses
- STACK_DIRECTION < 0 => grows toward lower addresses
- STACK_DIRECTION = 0 => direction of growth unknown */
-#undef STACK_DIRECTION
-
-/* Define to 1 if you have the ANSI C header files. */
-#undef STDC_HEADERS
-
-/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
-#undef TIME_WITH_SYS_TIME
-
-/* Define to 1 if your <sys/time.h> declares `struct tm'. */
-#undef TM_IN_SYS_TIME
-
-/* Version number of package */
-#undef VERSION
-
-/* Define to empty if `const' does not conform to ANSI C. */
-#undef const
-
-/* Define to `int' if <sys/types.h> doesn't define. */
-#undef gid_t
-
-/* Define to `int' if <sys/types.h> does not define. */
-#undef mode_t
-
-/* Define to `long int' if <sys/types.h> does not define. */
-#undef off_t
-
-/* Define to `int' if <sys/types.h> does not define. */
-#undef pid_t
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-#undef size_t
-
-/* Define to `int' if <sys/types.h> doesn't define. */
-#undef uid_t
-
-/* Define as `fork' if `vfork' does not work. */
-#undef vfork
AFPSERVER=-NO-
AUTHSERVER=-NO-
-AUTOMOUNT=-YES-
-NFSLOCKS=-AUTOMATIC-
-NISDOMAIN=-NO-
TIMESYNC=-NO-
QTSSERVER=-NO-
-WEBSERVER=-NO-
-SMBSERVER=-NO-
-SNMPSERVER=-NO-
#endif
-#define LAUNCH_KEY_SUBMITJOB "SubmitJob"
-#define LAUNCH_KEY_REMOVEJOB "RemoveJob"
-#define LAUNCH_KEY_STARTJOB "StartJob"
-#define LAUNCH_KEY_STOPJOB "StopJob"
-#define LAUNCH_KEY_GETJOB "GetJob"
-#define LAUNCH_KEY_GETJOBS "GetJobs"
-#define LAUNCH_KEY_CHECKIN "CheckIn"
-
-#define LAUNCH_JOBKEY_LABEL "Label"
-#define LAUNCH_JOBKEY_DISABLED "Disabled"
-#define LAUNCH_JOBKEY_USERNAME "UserName"
-#define LAUNCH_JOBKEY_GROUPNAME "GroupName"
-#define LAUNCH_JOBKEY_TIMEOUT "TimeOut"
-#define LAUNCH_JOBKEY_EXITTIMEOUT "ExitTimeOut"
-#define LAUNCH_JOBKEY_INITGROUPS "InitGroups"
-#define LAUNCH_JOBKEY_SOCKETS "Sockets"
-#define LAUNCH_JOBKEY_MACHSERVICES "MachServices"
-#define LAUNCH_JOBKEY_MACHSERVICELOOKUPPOLICIES "MachServiceLookupPolicies"
-#define LAUNCH_JOBKEY_INETDCOMPATIBILITY "inetdCompatibility"
-#define LAUNCH_JOBKEY_ENABLEGLOBBING "EnableGlobbing"
-#define LAUNCH_JOBKEY_PROGRAMARGUMENTS "ProgramArguments"
-#define LAUNCH_JOBKEY_PROGRAM "Program"
-#define LAUNCH_JOBKEY_ONDEMAND "OnDemand"
-#define LAUNCH_JOBKEY_KEEPALIVE "KeepAlive"
-#define LAUNCH_JOBKEY_LIMITLOADTOHOSTS "LimitLoadToHosts"
-#define LAUNCH_JOBKEY_LIMITLOADFROMHOSTS "LimitLoadFromHosts"
-#define LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE "LimitLoadToSessionType"
-#define LAUNCH_JOBKEY_RUNATLOAD "RunAtLoad"
-#define LAUNCH_JOBKEY_ROOTDIRECTORY "RootDirectory"
-#define LAUNCH_JOBKEY_WORKINGDIRECTORY "WorkingDirectory"
-#define LAUNCH_JOBKEY_ENVIRONMENTVARIABLES "EnvironmentVariables"
-#define LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES "UserEnvironmentVariables"
-#define LAUNCH_JOBKEY_UMASK "Umask"
-#define LAUNCH_JOBKEY_NICE "Nice"
-#define LAUNCH_JOBKEY_HOPEFULLYEXITSFIRST "HopefullyExitsFirst"
-#define LAUNCH_JOBKEY_HOPEFULLYEXITSLAST "HopefullyExitsLast"
-#define LAUNCH_JOBKEY_LOWPRIORITYIO "LowPriorityIO"
-#define LAUNCH_JOBKEY_SESSIONCREATE "SessionCreate"
-#define LAUNCH_JOBKEY_STARTONMOUNT "StartOnMount"
-#define LAUNCH_JOBKEY_SOFTRESOURCELIMITS "SoftResourceLimits"
-#define LAUNCH_JOBKEY_HARDRESOURCELIMITS "HardResourceLimits"
-#define LAUNCH_JOBKEY_STANDARDOUTPATH "StandardOutPath"
-#define LAUNCH_JOBKEY_STANDARDERRORPATH "StandardErrorPath"
-#define LAUNCH_JOBKEY_DEBUG "Debug"
-#define LAUNCH_JOBKEY_WAITFORDEBUGGER "WaitForDebugger"
-#define LAUNCH_JOBKEY_QUEUEDIRECTORIES "QueueDirectories"
-#define LAUNCH_JOBKEY_WATCHPATHS "WatchPaths"
-#define LAUNCH_JOBKEY_STARTINTERVAL "StartInterval"
-#define LAUNCH_JOBKEY_STARTCALENDARINTERVAL "StartCalendarInterval"
-#define LAUNCH_JOBKEY_BONJOURFDS "BonjourFDs"
-#define LAUNCH_JOBKEY_LASTEXITSTATUS "LastExitStatus"
-#define LAUNCH_JOBKEY_PID "PID"
-#define LAUNCH_JOBKEY_THROTTLEINTERVAL "ThrottleInterval"
-#define LAUNCH_JOBKEY_LAUNCHONLYONCE "LaunchOnlyOnce"
-#define LAUNCH_JOBKEY_ABANDONPROCESSGROUP "AbandonProcessGroup"
-#define LAUNCH_JOBKEY_POLICIES "Policies"
-
-#define LAUNCH_JOBPOLICY_DENYCREATINGOTHERJOBS "DenyCreatingOtherJobs"
-
-#define LAUNCH_JOBINETDCOMPATIBILITY_WAIT "Wait"
-
-#define LAUNCH_JOBKEY_MACH_RESETATCLOSE "ResetAtClose"
-#define LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN "HideUntilCheckIn"
-
-#define LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT "SuccessfulExit"
-#define LAUNCH_JOBKEY_KEEPALIVE_NETWORKSTATE "NetworkState"
-#define LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE "PathState"
-#define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBACTIVE "OtherJobActive"
-#define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBENABLED "OtherJobEnabled"
-
-#define LAUNCH_JOBKEY_CAL_MINUTE "Minute"
-#define LAUNCH_JOBKEY_CAL_HOUR "Hour"
-#define LAUNCH_JOBKEY_CAL_DAY "Day"
-#define LAUNCH_JOBKEY_CAL_WEEKDAY "Weekday"
-#define LAUNCH_JOBKEY_CAL_MONTH "Month"
-
-#define LAUNCH_JOBKEY_RESOURCELIMIT_CORE "Core"
-#define LAUNCH_JOBKEY_RESOURCELIMIT_CPU "CPU"
-#define LAUNCH_JOBKEY_RESOURCELIMIT_DATA "Data"
-#define LAUNCH_JOBKEY_RESOURCELIMIT_FSIZE "FileSize"
-#define LAUNCH_JOBKEY_RESOURCELIMIT_MEMLOCK "MemoryLock"
-#define LAUNCH_JOBKEY_RESOURCELIMIT_NOFILE "NumberOfFiles"
-#define LAUNCH_JOBKEY_RESOURCELIMIT_NPROC "NumberOfProcesses"
-#define LAUNCH_JOBKEY_RESOURCELIMIT_RSS "ResidentSetSize"
-#define LAUNCH_JOBKEY_RESOURCELIMIT_STACK "Stack"
-
-#define LAUNCH_JOBKEY_DISABLED_MACHINETYPE "MachineType"
-#define LAUNCH_JOBKEY_DISABLED_MODELNAME "ModelName"
-
-#define LAUNCH_JOBSOCKETKEY_TYPE "SockType"
-#define LAUNCH_JOBSOCKETKEY_PASSIVE "SockPassive"
-#define LAUNCH_JOBSOCKETKEY_BONJOUR "Bonjour"
-#define LAUNCH_JOBSOCKETKEY_SECUREWITHKEY "SecureSocketWithKey"
-#define LAUNCH_JOBSOCKETKEY_PATHNAME "SockPathName"
-#define LAUNCH_JOBSOCKETKEY_PATHMODE "SockPathMode"
-#define LAUNCH_JOBSOCKETKEY_NODENAME "SockNodeName"
-#define LAUNCH_JOBSOCKETKEY_SERVICENAME "SockServiceName"
-#define LAUNCH_JOBSOCKETKEY_FAMILY "SockFamily"
-#define LAUNCH_JOBSOCKETKEY_PROTOCOL "SockProtocol"
-#define LAUNCH_JOBSOCKETKEY_MULTICASTGROUP "MulticastGroup"
+#define LAUNCH_KEY_SUBMITJOB "SubmitJob"
+#define LAUNCH_KEY_REMOVEJOB "RemoveJob"
+#define LAUNCH_KEY_STARTJOB "StartJob"
+#define LAUNCH_KEY_STOPJOB "StopJob"
+#define LAUNCH_KEY_GETJOB "GetJob"
+#define LAUNCH_KEY_GETJOBS "GetJobs"
+#define LAUNCH_KEY_CHECKIN "CheckIn"
+
+#define LAUNCH_JOBKEY_LABEL "Label"
+#define LAUNCH_JOBKEY_DISABLED "Disabled"
+#define LAUNCH_JOBKEY_USERNAME "UserName"
+#define LAUNCH_JOBKEY_GROUPNAME "GroupName"
+#define LAUNCH_JOBKEY_TIMEOUT "TimeOut"
+#define LAUNCH_JOBKEY_EXITTIMEOUT "ExitTimeOut"
+#define LAUNCH_JOBKEY_INITGROUPS "InitGroups"
+#define LAUNCH_JOBKEY_SOCKETS "Sockets"
+#define LAUNCH_JOBKEY_MACHSERVICES "MachServices"
+#define LAUNCH_JOBKEY_MACHSERVICELOOKUPPOLICIES "MachServiceLookupPolicies"
+#define LAUNCH_JOBKEY_INETDCOMPATIBILITY "inetdCompatibility"
+#define LAUNCH_JOBKEY_ENABLEGLOBBING "EnableGlobbing"
+#define LAUNCH_JOBKEY_PROGRAMARGUMENTS "ProgramArguments"
+#define LAUNCH_JOBKEY_PROGRAM "Program"
+#define LAUNCH_JOBKEY_ONDEMAND "OnDemand"
+#define LAUNCH_JOBKEY_KEEPALIVE "KeepAlive"
+#define LAUNCH_JOBKEY_LIMITLOADTOHOSTS "LimitLoadToHosts"
+#define LAUNCH_JOBKEY_LIMITLOADFROMHOSTS "LimitLoadFromHosts"
+#define LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE "LimitLoadToSessionType"
+#define LAUNCH_JOBKEY_RUNATLOAD "RunAtLoad"
+#define LAUNCH_JOBKEY_ROOTDIRECTORY "RootDirectory"
+#define LAUNCH_JOBKEY_WORKINGDIRECTORY "WorkingDirectory"
+#define LAUNCH_JOBKEY_ENVIRONMENTVARIABLES "EnvironmentVariables"
+#define LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES "UserEnvironmentVariables"
+#define LAUNCH_JOBKEY_UMASK "Umask"
+#define LAUNCH_JOBKEY_NICE "Nice"
+#define LAUNCH_JOBKEY_HOPEFULLYEXITSFIRST "HopefullyExitsFirst"
+#define LAUNCH_JOBKEY_HOPEFULLYEXITSLAST "HopefullyExitsLast"
+#define LAUNCH_JOBKEY_LOWPRIORITYIO "LowPriorityIO"
+#define LAUNCH_JOBKEY_SESSIONCREATE "SessionCreate"
+#define LAUNCH_JOBKEY_STARTONMOUNT "StartOnMount"
+#define LAUNCH_JOBKEY_SOFTRESOURCELIMITS "SoftResourceLimits"
+#define LAUNCH_JOBKEY_HARDRESOURCELIMITS "HardResourceLimits"
+#define LAUNCH_JOBKEY_STANDARDINPATH "StandardInPath"
+#define LAUNCH_JOBKEY_STANDARDOUTPATH "StandardOutPath"
+#define LAUNCH_JOBKEY_STANDARDERRORPATH "StandardErrorPath"
+#define LAUNCH_JOBKEY_DEBUG "Debug"
+#define LAUNCH_JOBKEY_WAITFORDEBUGGER "WaitForDebugger"
+#define LAUNCH_JOBKEY_QUEUEDIRECTORIES "QueueDirectories"
+#define LAUNCH_JOBKEY_WATCHPATHS "WatchPaths"
+#define LAUNCH_JOBKEY_STARTINTERVAL "StartInterval"
+#define LAUNCH_JOBKEY_STARTCALENDARINTERVAL "StartCalendarInterval"
+#define LAUNCH_JOBKEY_BONJOURFDS "BonjourFDs"
+#define LAUNCH_JOBKEY_LASTEXITSTATUS "LastExitStatus"
+#define LAUNCH_JOBKEY_PID "PID"
+#define LAUNCH_JOBKEY_THROTTLEINTERVAL "ThrottleInterval"
+#define LAUNCH_JOBKEY_LAUNCHONLYONCE "LaunchOnlyOnce"
+#define LAUNCH_JOBKEY_ABANDONPROCESSGROUP "AbandonProcessGroup"
+#define LAUNCH_JOBKEY_IGNOREPROCESSGROUPATSHUTDOWN "IgnoreProcessGroupAtShutdown"
+#define LAUNCH_JOBKEY_POLICIES "Policies"
+#define LAUNCH_JOBKEY_ENABLETRANSACTIONS "EnableTransactions"
+
+#define LAUNCH_JOBPOLICY_DENYCREATINGOTHERJOBS "DenyCreatingOtherJobs"
+
+#define LAUNCH_JOBINETDCOMPATIBILITY_WAIT "Wait"
+
+#define LAUNCH_JOBKEY_MACH_RESETATCLOSE "ResetAtClose"
+#define LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN "HideUntilCheckIn"
+#define LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH "DrainMessagesOnCrash"
+
+#define LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT "SuccessfulExit"
+#define LAUNCH_JOBKEY_KEEPALIVE_NETWORKSTATE "NetworkState"
+#define LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE "PathState"
+#define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBACTIVE "OtherJobActive"
+#define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBENABLED "OtherJobEnabled"
+#define LAUNCH_JOBKEY_KEEPALIVE_AFTERINITIALDEMAND "AfterInitialDemand"
+
+#define LAUNCH_JOBKEY_CAL_MINUTE "Minute"
+#define LAUNCH_JOBKEY_CAL_HOUR "Hour"
+#define LAUNCH_JOBKEY_CAL_DAY "Day"
+#define LAUNCH_JOBKEY_CAL_WEEKDAY "Weekday"
+#define LAUNCH_JOBKEY_CAL_MONTH "Month"
+
+#define LAUNCH_JOBKEY_RESOURCELIMIT_CORE "Core"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_CPU "CPU"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_DATA "Data"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_FSIZE "FileSize"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_MEMLOCK "MemoryLock"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_NOFILE "NumberOfFiles"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_NPROC "NumberOfProcesses"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_RSS "ResidentSetSize"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_STACK "Stack"
+
+#define LAUNCH_JOBKEY_DISABLED_MACHINETYPE "MachineType"
+#define LAUNCH_JOBKEY_DISABLED_MODELNAME "ModelName"
+
+#define LAUNCH_JOBSOCKETKEY_TYPE "SockType"
+#define LAUNCH_JOBSOCKETKEY_PASSIVE "SockPassive"
+#define LAUNCH_JOBSOCKETKEY_BONJOUR "Bonjour"
+#define LAUNCH_JOBSOCKETKEY_SECUREWITHKEY "SecureSocketWithKey"
+#define LAUNCH_JOBSOCKETKEY_PATHNAME "SockPathName"
+#define LAUNCH_JOBSOCKETKEY_PATHMODE "SockPathMode"
+#define LAUNCH_JOBSOCKETKEY_NODENAME "SockNodeName"
+#define LAUNCH_JOBSOCKETKEY_SERVICENAME "SockServiceName"
+#define LAUNCH_JOBSOCKETKEY_FAMILY "SockFamily"
+#define LAUNCH_JOBSOCKETKEY_PROTOCOL "SockProtocol"
+#define LAUNCH_JOBSOCKETKEY_MULTICASTGROUP "MulticastGroup"
typedef struct _launch_data *launch_data_t;
#pragma GCC visibility push(default)
+#define LAUNCHD_DB_PREFIX "/var/db/launchd.db"
+
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);
#include <sys/types.h>
#include <launch.h>
#include <unistd.h>
+#include <paths.h>
+#include <uuid/uuid.h>
#pragma GCC visibility push(default)
__BEGIN_DECLS
-#define LAUNCH_KEY_SETUSERENVIRONMENT "SetUserEnvironment"
-#define LAUNCH_KEY_UNSETUSERENVIRONMENT "UnsetUserEnvironment"
-#define LAUNCH_KEY_SHUTDOWN "Shutdown"
-#define LAUNCH_KEY_SINGLEUSER "SingleUser"
-#define LAUNCH_KEY_GETRESOURCELIMITS "GetResourceLimits"
-#define LAUNCH_KEY_SETRESOURCELIMITS "SetResourceLimits"
-#define LAUNCH_KEY_GETRUSAGESELF "GetResourceUsageSelf"
-#define LAUNCH_KEY_GETRUSAGECHILDREN "GetResourceUsageChildren"
-
-#define LAUNCHD_SOCKET_ENV "LAUNCHD_SOCKET"
-#define LAUNCHD_SOCK_PREFIX "/var/tmp/launchd"
-#define LAUNCHD_TRUSTED_FD_ENV "__LAUNCHD_FD"
-#define LAUNCHD_ASYNC_MSG_KEY "_AsyncMessage"
-#define LAUNCH_KEY_BATCHCONTROL "BatchControl"
-#define LAUNCH_KEY_BATCHQUERY "BatchQuery"
-
-#define LAUNCH_JOBKEY_QUARANTINEDATA "QuarantineData"
-#define LAUNCH_JOBKEY_SANDBOXPROFILE "SandboxProfile"
-#define LAUNCH_JOBKEY_SANDBOXFLAGS "SandboxFlags"
-#define LAUNCH_JOBKEY_SANDBOX_NAMED "Named"
-
-#define LAUNCH_JOBKEY_ENTERKERNELDEBUGGERBEFOREKILL "EnterKernelDebuggerBeforeKill"
-#define LAUNCH_JOBKEY_PERJOBMACHSERVICES "PerJobMachServices"
-#define LAUNCH_JOBKEY_SERVICEIPC "ServiceIPC"
-#define LAUNCH_JOBKEY_BINARYORDERPREFERENCE "BinaryOrderPreference"
-#define LAUNCH_JOBKEY_MACHEXCEPTIONHANDLER "MachExceptionHandler"
-
-#define LAUNCH_JOBKEY_MACH_KUNCSERVER "kUNCServer"
-#define LAUNCH_JOBKEY_MACH_EXCEPTIONSERVER "ExceptionServer"
-#define LAUNCH_JOBKEY_MACH_TASKSPECIALPORT "TaskSpecialPort"
-#define LAUNCH_JOBKEY_MACH_HOSTSPECIALPORT "HostSpecialPort"
+#define LAUNCH_KEY_SETUSERENVIRONMENT "SetUserEnvironment"
+#define LAUNCH_KEY_UNSETUSERENVIRONMENT "UnsetUserEnvironment"
+#define LAUNCH_KEY_SHUTDOWN "Shutdown"
+#define LAUNCH_KEY_SINGLEUSER "SingleUser"
+#define LAUNCH_KEY_GETRESOURCELIMITS "GetResourceLimits"
+#define LAUNCH_KEY_SETRESOURCELIMITS "SetResourceLimits"
+#define LAUNCH_KEY_GETRUSAGESELF "GetResourceUsageSelf"
+#define LAUNCH_KEY_GETRUSAGECHILDREN "GetResourceUsageChildren"
+#define LAUNCH_KEY_SETPRIORITYLIST "SetPriorityList"
+
+#define LAUNCHD_SOCKET_ENV "LAUNCHD_SOCKET"
+#define LAUNCHD_SOCK_PREFIX _PATH_VARTMP "launchd"
+#define LAUNCHD_TRUSTED_FD_ENV "__LAUNCHD_FD"
+#define LAUNCHD_ASYNC_MSG_KEY "_AsyncMessage"
+#define LAUNCH_KEY_BATCHCONTROL "BatchControl"
+#define LAUNCH_KEY_BATCHQUERY "BatchQuery"
+#define LAUNCHD_DO_APPLE_INTERNAL_LOGGING "__DoAppleInternalLogging__"
+
+#define LAUNCH_KEY_JETSAMLABEL "JetsamLabel"
+#define LAUNCH_KEY_JETSAMFRONTMOST "JetsamFrontmost"
+#define LAUNCH_KEY_JETSAMPRIORITY "JetsamPriority"
+
+#define LAUNCH_JOBKEY_TRANSACTIONCOUNT "TransactionCount"
+#define LAUNCH_JOBKEY_QUARANTINEDATA "QuarantineData"
+#define LAUNCH_JOBKEY_SANDBOXPROFILE "SandboxProfile"
+#define LAUNCH_JOBKEY_SANDBOXFLAGS "SandboxFlags"
+#define LAUNCH_JOBKEY_SANDBOX_NAMED "Named"
+#define LAUNCH_JOBKEY_JETSAMPRIORITY "JetsamPriority"
+#define LAUNCH_JOBKEY_SECURITYSESSIONUUID "SecuritySessionUUID"
+
+#define LAUNCH_JOBKEY_EMBEDDEDPRIVILEGEDISPENSATION "EmbeddedPrivilegeDispensation"
+#define LAUNCH_JOBKEY_EMBEDDEDMAINTHREADPRIORITY "EmbeddedMainThreadPriority"
+
+#define LAUNCH_JOBKEY_ENTERKERNELDEBUGGERBEFOREKILL "EnterKernelDebuggerBeforeKill"
+#define LAUNCH_JOBKEY_PERJOBMACHSERVICES "PerJobMachServices"
+#define LAUNCH_JOBKEY_SERVICEIPC "ServiceIPC"
+#define LAUNCH_JOBKEY_BINARYORDERPREFERENCE "BinaryOrderPreference"
+#define LAUNCH_JOBKEY_MACHEXCEPTIONHANDLER "MachExceptionHandler"
+
+#define LAUNCH_JOBKEY_MACH_KUNCSERVER "kUNCServer"
+#define LAUNCH_JOBKEY_MACH_EXCEPTIONSERVER "ExceptionServer"
+#define LAUNCH_JOBKEY_MACH_TASKSPECIALPORT "TaskSpecialPort"
+#define LAUNCH_JOBKEY_MACH_HOSTSPECIALPORT "HostSpecialPort"
#define LAUNCH_JOBKEY_MACH_ENTERKERNELDEBUGGERONCLOSE "EnterKernelDebuggerOnClose"
typedef struct _launch *launch_t;
-launch_t launchd_fdopen(int);
+launch_t launchd_fdopen(int, int);
int launchd_getfd(launch_t);
void launchd_close(launch_t, __typeof__(close) closefunc);
*
* This returns 1 on success (it used to return otherwise), and -1 on failure.
*/
-#define LOAD_ONLY_SAFEMODE_LAUNCHAGENTS 1
+#define LOAD_ONLY_SAFEMODE_LAUNCHAGENTS 1 << 0
+#define LAUNCH_GLOBAL_ON_DEMAND 1 << 1
pid_t create_and_switch_to_per_session_launchd(const char * /* loginname */, int flags, ...);
/* Also for LoginWindow.
-.Dd September 30, 2004
+.Dd 1 May, 2009
.Dt launchctl 1
.Os Darwin
.Sh NAME
Load the specified configuration files or directories of configuration files.
Jobs that are not on-demand will be started as soon as possible.
All specified jobs will be loaded before any of them are allowed to start.
+Note that per-user configuration files (LaunchAgents) must be owned by the user
+loading them. All system-wide daemons (LaunchDaemons) must be owned by root. Configuration files
+must not be group- or world-writable. These restrictions are in place for security reasons,
+as allowing writability to a launchd configuration file allows one to specify which executable
+will be launched.
+.Pp
+Note that allowing non-root write access to the /System/Library/LaunchDaemons directory WILL render your system unbootable.
.Bl -tag -width -indent
.It Fl w
-Remove the disabled key and write the configuration files back out to disk.
+Overrides the Disabled key and sets it to false. In previous versions, this option
+would modify the configuration file. Now the state of the Disabled key is stored
+elsewhere on-disk.
.It Fl F
Force the loading of the plist. Ignore the Disabled key.
.It Fl S Ar sessiontype
This will also stop the job if it is running.
.Bl -tag -width -indent
.It Fl w
-Add the disabled key and write the configuration files back out to disk.
+Overrides the Disabled key and sets it to true. In previous versions, this option
+would modify the configuration file. Now the state of the Disabled key is stored
+elsewhere on-disk.
.It Fl S Ar sessiontype
Some jobs only make sense in certain contexts. This flag instructs
.Nm launchctl
restart the job if launchd finds any criteria that is satisfied.
Non-demand based jobs will always be restarted. Use of this subcommand is discouraged.
Jobs should ideally idle timeout by themselves.
-.It Ar list
-List all of the jobs loaded into
+.It Xo Ar list
+.Op Ar -x
+.Op Ar label
+.Xc
+With no arguments, list all of the jobs loaded into
+.Nm launchd
+in three columns. The first column displays the PID of the job if it is running.
+The second column displays the last exit status of the job. If the number in this
+column is negative, it represents the negative of the signal which killed the job.
+Thus, "-15" would indicate that the job was terminated with SIGTERM. The third column
+is the job's label.
+.Pp
+Note that you may see some jobs in the list whose labels are in the style "0xdeadbeef.anonymous.program".
+These are jobs which are not managed by
+.Nm launchd ,
+but, at one point, made a request to it.
+.Nm launchd
+claims no ownership and makes no guarantees regarding these jobs. They are stored purely for
+bookkeeping purposes.
+.Pp
+Similarly, you may see labels of the style "0xdeadbeef.mach_init.program". These are legacy jobs that run
+under mach_init emulation. This mechanism will be removed in future versions, and all remaining mach_init
+jobs should be converted over to
.Nm launchd .
+.Pp
+If
+.Op Ar label
+is specified, prints information about the requested job. If
+.Op Ar -x
+is specified, the information for the specified job is output as an XML property list.
.It Ar setenv Ar key Ar value
Set an environmental variable inside of
.Nm launchd .
.Xr umask 2
of
.Nm launchd .
-.It Ar bslist Op Ar PID
+.It Xo Ar bslist
+.Op Ar PID | ..
+.Op Ar -j
+.Xc
This prints out Mach bootstrap services and their respective states. While the
namespace appears flat, it is in fact hierarchical, thus allowing for certain
services to be only available to a subset of processes. The three states a
-service can be in are active ("A"), inactive ("I") and on-demand ("D").
+service can be in are active ("A"), inactive ("I") and on-demand ("D").
+.Pp
+If
+.Op Ar PID
+is specified, print the Mach bootstrap services available to that PID. If
+.Op Ar ..
+is specified, print the Mach bootstrap services available in the parent of the
+current bootstrap. Note that in Mac OS X v10.6, the per-user Mach bootstrap namespace
+is flat, so you will only see a different set of services in a per-user bootstrap
+if you are in an explicitly-created bootstrap subset.
+.Pp
+If
+.Op Ar -j
+is specified, each service name will be followed by the name of the job which registered
+it.
.It Ar bsexec Ar PID command Op Ar args
This executes the given command in the same Mach bootstrap namespace hierachy
as the given PID.
+.It Ar bstree Op Ar -j
+This prints a hierarchical view of the entire Mach bootstrap tree. If
+.Op Ar -j
+is specified, each service name will be followed by the name of the job which registered it.
+Requires root
+privileges.
+.It Ar managerpid
+This prints the PID of the launchd which manages the current bootstrap.
+.It Ar manageruid
+This prints the UID of the launchd which manages the current bootstrap.
+.It Ar managername
+This prints the name of the launchd job manager which manages the current bootstrap.
+See LimitLoadToSessionType in
+.Xr launchd.plist 5
+for more details.
.It Ar help
Print out a quick usage statement.
.El
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
-static const char *const __rcs_file_version__ = "$Revision: 23887 $";
+static const char *const __rcs_file_version__ = "$Revision: 23930 $";
#include "config.h"
#include "launch.h"
#include "vproc.h"
#include "vproc_priv.h"
#include "vproc_internal.h"
+#include "bootstrap_priv.h"
+#include "launch_internal.h"
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFPriv.h>
+#include <CoreFoundation/CFLogUtilities.h>
#include <TargetConditionals.h>
#if HAVE_SECURITY
#include <Security/Security.h>
#include <sys/sysctl.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#ifndef SO_EXECPATH
+/* This is just so it's easy for me to compile launchctl without buildit. */
+ #define SO_EXECPATH 0x1085
+#endif
#include <sys/un.h>
#include <sys/fcntl.h>
#include <sys/event.h>
#include <bootfiles.h>
#include <sysexits.h>
#include <util.h>
+#include <spawn.h>
+#include <sys/syslimits.h>
+
+#if HAVE_LIBAUDITD
+#include <bsm/auditd_lib.h>
+#ifndef AUDITD_PLIST_FILE
+#define AUDITD_PLIST_FILE "/System/Library/LaunchDaemons/com.apple.auditd.plist"
+#endif
+#endif
+extern char **environ;
-#define LAUNCH_SECDIR "/tmp/launch-XXXXXX"
+
+#define LAUNCH_SECDIR _PATH_TMP "launch-XXXXXX"
#define MACHINIT_JOBKEY_ONDEMAND "OnDemand"
#define MACHINIT_JOBKEY_SERVICENAME "ServiceName"
#define assumes(e) \
(__builtin_expect(!(e), 0) ? _log_launchctl_bug(__rcs_file_version__, __FILE__, __LINE__, #e), false : true)
+#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;
- unsigned int editondisk:1, load:1, forceload:1, __pad:29;
+ bool editondisk:1, load:1, forceload:1;
};
static void myCFDictionaryApplyFunction(const void *key, const void *value, void *context);
+static void job_override(CFTypeRef key, CFTypeRef val, CFMutableDictionaryRef job);
+static CFTypeRef CFTypeCreateFromLaunchData(launch_data_t obj);
+static CFArrayRef CFArrayCreateFromLaunchArray(launch_data_t arr);
+static CFDictionaryRef CFDictionaryCreateFromLaunchDictionary(launch_data_t dict);
static bool launch_data_array_append(launch_data_t a, launch_data_t o);
static void distill_jobs(launch_data_t);
static void distill_config_file(launch_data_t);
static launch_data_t CF2launch_data(CFTypeRef);
static launch_data_t read_plist_file(const char *file, bool editondisk, bool load);
static CFPropertyListRef CreateMyPropertyListFromFile(const char *);
+static CFPropertyListRef CFPropertyListCreateFromFile(CFURLRef plistURL);
static void WriteMyPropertyListToFile(CFPropertyListRef, const char *);
static bool path_goodness_check(const char *path, bool forceload);
static void readpath(const char *, struct load_unload_state *);
static void _log_launchctl_bug(const char *rcs_rev, const char *path, unsigned int line, const char *test);
static void loopback_setup_ipv4(void);
static void loopback_setup_ipv6(void);
-static pid_t fwexec(const char *const *argv, bool _wait);
+static pid_t fwexec(const char *const *argv, int *wstatus);
static void do_potential_fsck(void);
static bool path_check(const char *path);
static bool is_safeboot(void);
static void do_bootroot_magic(void);
static void do_single_user_mode(bool);
static bool do_single_user_mode2(void);
+static void do_crash_debug_mode(void);
+static bool do_crash_debug_mode2(void);
static void read_launchd_conf(void);
+static void read_environment_dot_plist(void);
static bool job_disabled_logic(launch_data_t obj);
static void fix_bogus_file_metadata(void);
+static void do_file_init(void) __attribute__((constructor));
+static void setup_system_context(void);
+static void handle_system_bootstrapper_crashes_separately(void);
+static void fatal_signal_handler(int sig, siginfo_t *si, void *uap);
typedef enum {
BOOTCACHE_START = 1,
static int setenv_cmd(int argc, char *const argv[]);
static int unsetenv_cmd(int argc, char *const argv[]);
static int getenv_and_export_cmd(int argc, char *const argv[]);
+static int wait4debugger_cmd(int argc, char *const argv[]);
static int limit_cmd(int argc, char *const argv[]);
static int stdio_cmd(int argc, char *const argv[]);
static int umask_cmd(int argc, char *const argv[]);
static int getrusage_cmd(int argc, char *const argv[]);
static int bsexec_cmd(int argc, char *const argv[]);
+static int _bslist_cmd(mach_port_t bport, unsigned int depth, bool show_job, bool local_only);
static int bslist_cmd(int argc, char *const argv[]);
-
+static int _bstree_cmd(mach_port_t bsport, unsigned int depth, bool show_jobs);
+static int bstree_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 exit_cmd(int argc, char *const argv[]) __attribute__((noreturn));
static int help_cmd(int argc, char *const argv[]);
int (*func)(int argc, char *const argv[]);
const char *desc;
} cmds[] = {
- { "load", load_and_unload_cmd, "Load configuration files and/or directories" },
- { "unload", load_and_unload_cmd, "Unload configuration files and/or directories" },
-// { "reload", reload_cmd, "Reload configuration files and/or directories" },
- { "start", start_stop_remove_cmd, "Start specified job" },
- { "stop", start_stop_remove_cmd, "Stop specified job" },
- { "submit", submit_cmd, "Submit a job from the command line" },
- { "remove", start_stop_remove_cmd, "Remove specified job" },
- { "bootstrap", bootstrap_cmd, "Bootstrap launchd" },
- { "list", list_cmd, "List jobs and information about jobs" },
- { "setenv", setenv_cmd, "Set an environmental variable in launchd" },
- { "unsetenv", unsetenv_cmd, "Unset an environmental variable in launchd" },
- { "getenv", getenv_and_export_cmd, "Get an environmental variable from launchd" },
- { "export", getenv_and_export_cmd, "Export shell settings from launchd" },
- { "limit", limit_cmd, "View and adjust launchd resource limits" },
- { "stdout", stdio_cmd, "Redirect launchd's standard out to the given path" },
- { "stderr", stdio_cmd, "Redirect launchd's standard error to the given path" },
- { "shutdown", fyi_cmd, "Prepare for system shutdown" },
- { "singleuser", fyi_cmd, "Switch to single-user mode" },
- { "getrusage", getrusage_cmd, "Get resource usage statistics from launchd" },
- { "log", logupdate_cmd, "Adjust the logging level or mask of launchd" },
- { "umask", umask_cmd, "Change launchd's umask" },
- { "bsexec", bsexec_cmd, "Execute a process within a different Mach bootstrap subset" },
- { "bslist", bslist_cmd, "List Mach bootstrap services and optional servers" },
- { "exit", exit_cmd, "Exit the interactive invocation of launchctl" },
- { "quit", exit_cmd, "Quit the interactive invocation of launchctl" },
- { "help", help_cmd, "This help output" },
+ { "load", load_and_unload_cmd, "Load configuration files and/or directories" },
+ { "unload", load_and_unload_cmd, "Unload configuration files and/or directories" },
+// { "reload", reload_cmd, "Reload configuration files and/or directories" },
+ { "start", start_stop_remove_cmd, "Start specified job" },
+ { "stop", start_stop_remove_cmd, "Stop specified job" },
+ { "submit", submit_cmd, "Submit a job from the command line" },
+ { "remove", start_stop_remove_cmd, "Remove specified job" },
+ { "bootstrap", bootstrap_cmd, "Bootstrap launchd" },
+ { "list", list_cmd, "List jobs and information about jobs" },
+ { "setenv", setenv_cmd, "Set an environmental variable in launchd" },
+ { "unsetenv", unsetenv_cmd, "Unset an environmental variable in launchd" },
+ { "getenv", getenv_and_export_cmd, "Get an environmental variable from launchd" },
+ { "export", getenv_and_export_cmd, "Export shell settings from launchd" },
+ { "debug", wait4debugger_cmd, "Set the WaitForDebugger flag for the target job to true." },
+ { "limit", limit_cmd, "View and adjust launchd resource limits" },
+ { "stdout", stdio_cmd, "Redirect launchd's standard out to the given path" },
+ { "stderr", stdio_cmd, "Redirect launchd's standard error to the given path" },
+ { "shutdown", fyi_cmd, "Prepare for system shutdown" },
+ { "singleuser", fyi_cmd, "Switch to single-user mode" },
+ { "getrusage", getrusage_cmd, "Get resource usage statistics from launchd" },
+ { "log", logupdate_cmd, "Adjust the logging level or mask of launchd" },
+ { "umask", umask_cmd, "Change launchd's umask" },
+ { "bsexec", bsexec_cmd, "Execute a process within a different Mach bootstrap subset" },
+ { "bslist", bslist_cmd, "List Mach bootstrap services and optional servers" },
+ { "bstree", bstree_cmd, "Show the entire Mach bootstrap tree. Requires root privileges." },
+ { "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." },
+ { "exit", exit_cmd, "Exit the interactive invocation of launchctl" },
+ { "quit", exit_cmd, "Quit the interactive invocation of launchctl" },
+ { "help", help_cmd, "This help output" },
};
static bool istty;
static bool verbose;
static bool is_managed;
+static bool do_apple_internal_magic;
+static bool system_context;
+static bool rootuser_context;
+static bool bootstrapping_system;
+static bool bootstrapping_peruser;
+static bool g_verbose_boot = false;
+
+static bool g_job_overrides_db_has_changed = false;
+static CFMutableDictionaryRef g_job_overrides_db = NULL;
+static char g_job_overrides_db_path[PATH_MAX];
+
+#if 0
+static bool g_job_cache_db_has_changed = false;
+static launch_data_t g_job_cache_db = NULL;
+static char g_job_cache_db_path[PATH_MAX];
+#endif
int
main(int argc, char *const argv[])
if (vproc_swap_integer(NULL, VPROC_GSK_IS_MANAGED, NULL, &is_managed_val) == NULL && is_managed_val) {
is_managed = true;
}
-
- if (getuid() == 0 && !is_managed) {
- mach_port_t root_bs = str2bsport("/");
- task_set_bootstrap_port(mach_task_self(), root_bs);
- mach_port_deallocate(mach_task_self(), bootstrap_port);
- bootstrap_port = root_bs;
- }
-
+
istty = isatty(STDIN_FILENO);
-
argc--, argv++;
-
+
if (argc > 0 && argv[0][0] == '-') {
char *flago;
case 'v':
verbose = true;
break;
+ case 'u':
+ if( argc > 1 ) {
+ if( strncmp(argv[1], "root", sizeof("root")) == 0 ) {
+ rootuser_context = true;
+ } else {
+ fprintf(stderr, "Unknown user: %s\n", argv[1]);
+ exit(EXIT_FAILURE);
+ }
+ argc--, argv++;
+ } else {
+ fprintf(stderr, "-u option requires an argument. Currently, only \"root\" is supported.\n");
+ }
+ break;
+ case '1':
+ system_context = true;
+ break;
default:
fprintf(stderr, "Unknown argument: '-%c'\n", *flago);
break;
argc--, 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.
+ */
+ if( rootuser_context ) {
+ 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 ) {
+ 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) ) {
+ /* 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 );
+ }
+
+ 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);
+ }
+ } else if( rootuser_context ) {
+ if( getuid() != 0 ) {
+ fprintf(stderr, "You must be root to run in the root user context.\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
if (NULL == readline) {
fprintf(stderr, "missing library: readline\n");
exit(EXIT_FAILURE);
optind = 1;
optreset = 1;
-
+
for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++) {
if (!strcmp(cmds[i].name, argv[0])) {
return cmds[i].func(argc, argv);
{
char s[1000], *c, *av[100];
const char *file;
- size_t len, i;
+ size_t len;
+ int i;
FILE *f;
if (getppid() == 1) {
return;
}
- while ((c = fgets(s, sizeof(s), f))) {
+ while ((c = fgets(s, (int) sizeof s, f))) {
len = strlen(c);
if (len && c[len - 1] == '\n') {
c[len - 1] = '\0';
fclose(f);
}
+CFPropertyListRef CFPropertyListCreateFromFile(CFURLRef plistURL)
+{
+ CFReadStreamRef plistReadStream = CFReadStreamCreateWithFile(NULL, plistURL);
+
+ CFErrorRef streamErr = NULL;
+ if( !CFReadStreamOpen(plistReadStream) ) {
+ streamErr = CFReadStreamCopyError(plistReadStream);
+ CFStringRef errString = CFErrorCopyDescription(streamErr);
+
+ CFShow(errString);
+
+ CFRelease(errString);
+ CFRelease(streamErr);
+ }
+
+ CFPropertyListRef plist = NULL;
+ if( plistReadStream ) {
+ CFStringRef errString = NULL;
+ CFPropertyListFormat plistFormat = 0;
+ plist = CFPropertyListCreateFromStream(NULL, plistReadStream, 0, kCFPropertyListImmutable, &plistFormat, &errString);
+ if( !plist ) {
+ CFShow(errString);
+ CFRelease(errString);
+ }
+ }
+
+ CFReadStreamClose(plistReadStream);
+ CFRelease(plistReadStream);
+
+ return plist;
+}
+
+#define CFReleaseIfNotNULL(cf) if( cf ) CFRelease(cf);
+void
+read_environment_dot_plist(void)
+{
+ CFStringRef plistPath = NULL;
+ CFURLRef plistURL = NULL;
+ CFDictionaryRef envPlist = NULL;
+ launch_data_t req = NULL, launch_env_dict = NULL, resp = NULL;
+
+ char plist_path_str[PATH_MAX];
+ plist_path_str[PATH_MAX - 1] = 0;
+ snprintf(plist_path_str, sizeof(plist_path_str), "%s/.MacOSX/environment.plist", getenv("HOME"));
+
+ struct stat sb;
+ if( stat(plist_path_str, &sb) == -1 ) {
+ goto out;
+ }
+
+ plistPath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), plist_path_str);
+ if( !assumes(plistPath != NULL) ) {
+ goto out;
+ }
+
+ plistURL = CFURLCreateWithFileSystemPath(NULL, plistPath, kCFURLPOSIXPathStyle, false);
+ if( !assumes(plistURL != NULL) ) {
+ goto out;
+ }
+
+ envPlist = (CFDictionaryRef)CFPropertyListCreateFromFile(plistURL);
+ if( !assumes(envPlist != NULL) ) {
+ goto out;
+ }
+
+ launch_env_dict = CF2launch_data(envPlist);
+ if( !assumes(launch_env_dict != NULL) ) {
+ goto out;
+ }
+
+ req = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
+ if( !assumes(req != NULL) ) {
+ goto out;
+ }
+
+ launch_data_dict_insert(req, launch_env_dict, LAUNCH_KEY_SETUSERENVIRONMENT);
+ resp = launch_msg(req);
+ if( !assumes(resp != NULL) ) {
+ goto out;
+ }
+
+ if( !assumes(launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) ) {
+ goto out;
+ }
+
+ assumes(launch_data_get_errno(resp) == 0);
+out:
+ CFReleaseIfNotNULL(plistPath);
+ CFReleaseIfNotNULL(plistURL);
+ CFReleaseIfNotNULL(envPlist);
+ if( req ) {
+ launch_data_free(req);
+ }
+
+ if( resp ) {
+ launch_data_free(resp);
+ }
+}
+
int
unsetenv_cmd(int argc, char *const argv[])
{
return 0;
}
+int
+wait4debugger_cmd(int argc, char * const argv[])
+{
+ if( argc != 3 ) {
+ 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 ) {
+ inval = 1;
+ } else if( strncmp(argv[2], "false", sizeof("false")) != 0 ) {
+ inval = atoi(argv[2]);
+ inval &= 1;
+ }
+
+ vproc_t vp = vprocmgr_lookup_vproc(argv[1]);
+ if( vp ) {
+ vproc_err_t verr = vproc_swap_integer(vp, VPROC_GSK_WAITFORDEBUGGER, &inval, NULL);
+ if( verr ) {
+ fprintf(stderr, "Failed to set WaitForDebugger flag on %s.\n", argv[1]);
+ } else {
+ result = 0;
+ }
+ vproc_release(vp);
+ }
+
+ return result;
+}
+
void
unloadjob(launch_data_t job)
{
}
}
+void
+job_override(CFTypeRef key, CFTypeRef val, CFMutableDictionaryRef job)
+{
+ if( !CFTypeCheck(key, CFString) ) {
+ return;
+ }
+ if( CFStringCompare(key, CFSTR(LAUNCH_JOBKEY_LABEL), kCFCompareCaseInsensitive) == 0 ) {
+ return;
+ }
+
+ CFDictionarySetValue(job, key, val);
+}
+
launch_data_t
read_plist_file(const char *file, bool editondisk, bool load)
{
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;
}
- if (editondisk) {
- if (load) {
- CFDictionaryRemoveValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_DISABLED));
+ CFStringRef label = CFDictionaryGetValue(plist, CFSTR(LAUNCH_JOBKEY_LABEL));
+ if( g_job_overrides_db && label && CFTypeCheck(label, CFString) ) {
+ CFDictionaryRef overrides = CFDictionaryGetValue(g_job_overrides_db, label);
+ if( overrides && CFTypeCheck(overrides, CFDictionary) ) {
+ CFDictionaryApplyFunction(overrides, (CFDictionaryApplierFunction)job_override, (void *)plist);
+ }
+ }
+
+ if( editondisk ) {
+ if( g_job_overrides_db ) {
+ CFMutableDictionaryRef job = (CFMutableDictionaryRef)CFDictionaryGetValue(g_job_overrides_db, label);
+ if( !job || !CFTypeCheck(job, CFDictionary) ) {
+ job = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFDictionarySetValue(g_job_overrides_db, label, job);
+ CFRelease(job);
+ }
+
+ CFDictionarySetValue(job, CFSTR(LAUNCH_JOBKEY_DISABLED), load ? kCFBooleanFalse : kCFBooleanTrue);
+ CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_DISABLED), load ? kCFBooleanFalse : kCFBooleanTrue);
+ g_job_overrides_db_has_changed = true;
} else {
- CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_DISABLED), kCFBooleanTrue);
+ if (load) {
+ CFDictionaryRemoveValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_DISABLED));
+ } else {
+ CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_DISABLED), kCFBooleanTrue);
+ }
+ WriteMyPropertyListToFile(plist, file);
}
- WriteMyPropertyListToFile(plist, file);
}
r = CF2launch_data(plist);
if (job_disabled && lus->load) {
goto out_bad;
}
+
+ if( bootstrapping_system || bootstrapping_peruser ) {
+ uuid_t uuid;
+ uuid_clear(uuid);
+
+ launch_data_t uuid_d = launch_data_new_opaque(uuid, sizeof(uuid_t));
+ launch_data_dict_insert(thejob, uuid_d, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
+ }
if (delay_to_second_pass(thejob)) {
launch_data_array_append(lus->pass2, thejob);
job_disabled_logic(launch_data_t obj)
{
bool r = false;
-
+
switch (launch_data_get_type(obj)) {
- case LAUNCH_DATA_DICTIONARY:
- launch_data_dict_iterate(obj, job_disabled_dict_logic, &r);
- break;
- case LAUNCH_DATA_BOOL:
- r = launch_data_get_bool(obj);
- break;
- default:
- break;
+ case LAUNCH_DATA_DICTIONARY:
+ launch_data_dict_iterate(obj, job_disabled_dict_logic, &r);
+ break;
+ case LAUNCH_DATA_BOOL:
+ r = launch_data_get_bool(obj);
+ break;
+ default:
+ break;
}
-
+
return r;
}
return;
}
oldmask = umask(S_IRWXG|S_IRWXO);
- if (bind(sfd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
+ if (bind(sfd, (struct sockaddr *)&sun, (socklen_t) sizeof sun) == -1) {
close(sfd);
umask(oldmask);
return;
if (setm) {
chmod(sun.sun_path, sun_mode);
}
- if ((st == SOCK_STREAM || st == SOCK_SEQPACKET) && listen(sfd, SOMAXCONN) == -1) {
+ if ((st == SOCK_STREAM || st == SOCK_SEQPACKET) && listen(sfd, -1) == -1) {
close(sfd);
return;
}
- } else if (connect(sfd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
+ } else if (connect(sfd, (struct sockaddr *)&sun, (socklen_t) sizeof sun) == -1) {
close(sfd);
return;
}
if (hints.ai_flags & AI_PASSIVE) {
if (AF_INET6 == res->ai_family && -1 == setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY,
- (void *)&sock_opt, sizeof(sock_opt))) {
+ (void *)&sock_opt, (socklen_t) sizeof sock_opt)) {
fprintf(stderr, "setsockopt(IPV6_V6ONLY): %m");
return;
}
if (mgroup) {
- if (setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, (void *)&sock_opt, sizeof(sock_opt)) == -1) {
+ if (setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, (void *)&sock_opt, (socklen_t) sizeof sock_opt) == -1) {
fprintf(stderr, "setsockopt(SO_REUSEPORT): %s\n", strerror(errno));
return;
}
} else {
- if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt, sizeof(sock_opt)) == -1) {
+ if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt, (socklen_t) sizeof sock_opt) == -1) {
fprintf(stderr, "setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
return;
}
if (mgroup) {
do_mgroup_join(sfd, res->ai_family, res->ai_socktype, res->ai_protocol, mgroup);
}
- if ((res->ai_socktype == SOCK_STREAM || res->ai_socktype == SOCK_SEQPACKET) && listen(sfd, SOMAXCONN) == -1) {
+ if ((res->ai_socktype == SOCK_STREAM || res->ai_socktype == SOCK_SEQPACKET) && listen(sfd, -1) == -1) {
fprintf(stderr, "listen(): %s\n", strerror(errno));
return;
}
if (AF_INET == family) {
memset(&mreq, 0, sizeof(mreq));
mreq.imr_multiaddr = ((struct sockaddr_in *)res->ai_addr)->sin_addr;
- if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
+ if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, (socklen_t) sizeof mreq) == -1) {
fprintf(stderr, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
continue;
}
} else if (AF_INET6 == family) {
memset(&m6req, 0, sizeof(m6req));
m6req.ipv6mr_multiaddr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &m6req, sizeof(m6req)) == -1) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &m6req, (socklen_t) sizeof m6req) == -1) {
fprintf(stderr, "setsockopt(IPV6_JOIN_GROUP): %s\n", strerror(errno));
continue;
}
if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) {
fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode);
}
- propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString);
- if (!propertyList) {
- fprintf(stderr, "%s: propertyList is NULL\n", getprogname());
+
+ propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainersAndLeaves, &errorString);
+ if( fileURL ) {
+ CFRelease(fileURL);
+ }
+
+ if( resourceData ) {
+ CFRelease(resourceData);
}
return propertyList;
if (!CFURLWriteDataAndPropertiesToResource(fileURL, resourceData, NULL, &errorCode)) {
fprintf(stderr, "%s: CFURLWriteDataAndPropertiesToResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode);
}
+
+ if( resourceData ) {
+ CFRelease(resourceData);
+ }
+}
+
+static inline Boolean __is_launch_data_t(launch_data_t obj)
+{
+ Boolean result = true;
+
+ switch( launch_data_get_type(obj) ) {
+ case LAUNCH_DATA_STRING : break;
+ case LAUNCH_DATA_INTEGER : break;
+ case LAUNCH_DATA_REAL : break;
+ case LAUNCH_DATA_BOOL : break;
+ case LAUNCH_DATA_ARRAY : break;
+ case LAUNCH_DATA_DICTIONARY : break;
+ case LAUNCH_DATA_FD : break;
+ case LAUNCH_DATA_MACHPORT : break;
+ default : result = false;
+ }
+
+ return result;
+}
+
+static void __launch_data_iterate(launch_data_t obj, const char *key, CFMutableDictionaryRef dict)
+{
+ if( obj && __is_launch_data_t(obj) ) {
+ CFStringRef cfKey = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
+ CFTypeRef cfVal = CFTypeCreateFromLaunchData(obj);
+
+ if( cfVal ) {
+ CFDictionarySetValue(dict, cfKey, cfVal);
+ CFRelease(cfVal);
+ }
+ CFRelease(cfKey);
+ }
+}
+
+static CFTypeRef CFTypeCreateFromLaunchData(launch_data_t obj)
+{
+ CFTypeRef cfObj = NULL;
+
+ switch( launch_data_get_type(obj) ) {
+ case LAUNCH_DATA_STRING :
+ {
+ const char *str = launch_data_get_string(obj);
+ cfObj = CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
+
+ break;
+ }
+ case LAUNCH_DATA_INTEGER :
+ {
+ long long integer = launch_data_get_integer(obj);
+ cfObj = CFNumberCreate(NULL, kCFNumberLongLongType, &integer);
+
+ break;
+ }
+ case LAUNCH_DATA_REAL :
+ {
+ double real = launch_data_get_real(obj);
+ cfObj = CFNumberCreate(NULL, kCFNumberDoubleType, &real);
+
+ break;
+ }
+ case LAUNCH_DATA_BOOL :
+ {
+ bool yesno = launch_data_get_bool(obj);
+ cfObj = yesno ? kCFBooleanTrue : kCFBooleanFalse;
+
+ break;
+ }
+ case LAUNCH_DATA_ARRAY :
+ {
+ cfObj = (CFTypeRef)CFArrayCreateFromLaunchArray(obj);
+
+ break;
+ }
+ case LAUNCH_DATA_DICTIONARY :
+ {
+ cfObj = (CFTypeRef)CFDictionaryCreateFromLaunchDictionary(obj);
+
+ break;
+ }
+ case LAUNCH_DATA_FD :
+ {
+ int fd = launch_data_get_fd(obj);
+ cfObj = CFNumberCreate(NULL, kCFNumberIntType, &fd);
+
+ break;
+ }
+ case LAUNCH_DATA_MACHPORT :
+ {
+ mach_port_t port = launch_data_get_machport(obj);
+ cfObj = CFNumberCreate(NULL, kCFNumberIntType, &port);
+
+ break;
+ }
+ default : break;
+ }
+
+ return cfObj;
+}
+
+#pragma mark CFArray
+CFArrayRef CFArrayCreateFromLaunchArray(launch_data_t arr)
+{
+ CFArrayRef result = NULL;
+ CFMutableArrayRef mutResult = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ if( launch_data_get_type(arr) == LAUNCH_DATA_ARRAY ) {
+ unsigned int count = launch_data_array_get_count(arr);
+ unsigned int i = 0;
+
+ for( i = 0; i < count; i++ ) {
+ launch_data_t launch_obj = launch_data_array_get_index(arr, i);
+ CFTypeRef obj = CFTypeCreateFromLaunchData(launch_obj);
+
+ if( obj ) {
+ CFArrayAppendValue(mutResult, obj);
+ CFRelease(obj);
+ }
+ }
+
+ result = CFArrayCreateCopy(NULL, mutResult);
+ }
+
+ if( mutResult ) {
+ CFRelease(mutResult);
+ }
+ return result;
+}
+
+#pragma mark CFDictionary / CFPropertyList
+static CFDictionaryRef CFDictionaryCreateFromLaunchDictionary(launch_data_t dict)
+{
+ CFDictionaryRef result = NULL;
+
+ 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);
+
+ result = CFDictionaryCreateCopy(NULL, mutResult);
+ CFRelease(mutResult);
+ }
+
+ return result;
}
void
help_cmd(int argc, char *const argv[])
{
FILE *where = stdout;
- int l, cmdwidth = 0;
- size_t i;
+ size_t i, l, cmdwidth = 0;
if (argc == 0 || argv == NULL)
where = stderr;
for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++) {
l = strlen(cmds[i].name);
- if (l > cmdwidth)
+ if (l > cmdwidth) {
cmdwidth = l;
+ }
}
for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++) {
- fprintf(where, "\t%-*s\t%s\n", cmdwidth, cmds[i].name, cmds[i].desc);
+ fprintf(where, "\t%-*s\t%s\n", (int)cmdwidth, cmds[i].name, cmds[i].desc);
}
return 0;
if (!assumes(login_tty(fd) != -1)) {
_exit(EXIT_FAILURE);
}
+
+ mach_timespec_t wt = { 5, 0 };
+ IOKitWaitQuiet(kIOMasterPortDefault, &wt); /* This will hopefully return after all the kexts have shut up. */
+
setenv("TERM", "vt100", 1);
if (runcom_fsck) {
fprintf(stdout, "Singleuser boot -- fsck not done\n");
_exit(EXIT_FAILURE);
}
+void
+do_crash_debug_mode(void)
+{
+ while (!do_crash_debug_mode2()) {
+ sleep(1);
+ }
+}
+
+bool
+do_crash_debug_mode2(void)
+{
+ int wstatus;
+ int fd;
+ pid_t p;
+
+ switch ((p = fork())) {
+ case -1:
+ syslog(LOG_ERR, "can't fork crash debug shell, trying again: %m");
+ return false;
+ case 0:
+ break;
+ default:
+ assumes(waitpid(p, &wstatus, 0) != -1);
+ if (WIFEXITED(wstatus)) {
+ if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) {
+ return true;
+ } else {
+ fprintf(stdout, "crash debug mode: exit status: %d\n", WEXITSTATUS(wstatus));
+ }
+ } else {
+ fprintf(stdout, "crash debug mode shell: %s\n", strsignal(WTERMSIG(wstatus)));
+ }
+ return false;
+ }
+
+ revoke(_PATH_CONSOLE);
+ if (!assumes((fd = open(_PATH_CONSOLE, O_RDWR)) != -1)) {
+ _exit(EXIT_FAILURE);
+ }
+ if (!assumes(login_tty(fd) != -1)) {
+ _exit(EXIT_FAILURE);
+ }
+
+ mach_timespec_t wt = { 5, 0 };
+ IOKitWaitQuiet(kIOMasterPortDefault, &wt); /* This will hopefully return after all the kexts have shut up. */
+
+ setenv("TERM", "vt100", 1);
+ fprintf(stdout, "Entering boot-time debugging mode...\n");
+ fprintf(stdout, "The system bootstrapper process has crashed. To debug:\n");
+ fprintf(stdout, "\tgdb attach %i\n", getppid());
+ fprintf(stdout, "You can try booting the system with:\n");
+ fprintf(stdout, "\tlaunchctl load -S System -D All\n\n");
+
+ execl(_PATH_BSHELL, "-sh", NULL);
+ syslog(LOG_ERR, "can't exec %s for crash debug: %m", _PATH_BSHELL);
+ _exit(EXIT_FAILURE);
+}
+
+static void
+exit_at_sigterm(int sig)
+{
+ if( sig == SIGTERM ) {
+ _exit(EXIT_SUCCESS);
+ }
+}
+
+void
+fatal_signal_handler(int sig __attribute__((unused)), siginfo_t *si __attribute__((unused)), void *uap __attribute__((unused)))
+{
+ do_crash_debug_mode();
+}
+
+void
+handle_system_bootstrapper_crashes_separately(void)
+{
+ if( !g_verbose_boot ) {
+ return;
+ }
+
+ 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);
+}
+
static void
system_specific_bootstrap(bool sflag)
{
int hnmib[] = { CTL_KERN, KERN_HOSTNAME };
struct kevent kev;
int kq;
-
+#if HAVE_LIBAUDITD
+ launch_data_t lda, ldb;
+#endif
do_sysversion_sysctl();
loopback_setup_ipv4();
loopback_setup_ipv6();
+ apply_sysctls_from_file("/etc/sysctl.conf");
+
#if TARGET_OS_EMBEDDED
if (path_check("/etc/rc.boot")) {
const char *rcboot_tool[] = { "/etc/rc.boot", NULL };
- assumes(fwexec(rcboot_tool, true) != -1);
+
+ assumes(signal(SIGTERM, exit_at_sigterm) != SIG_ERR);
+ assumes(fwexec(rcboot_tool, NULL) != -1);
}
#endif
- apply_sysctls_from_file("/etc/sysctl.conf");
-
if (path_check("/etc/rc.cdrom")) {
const char *rccdrom_tool[] = { _PATH_BSHELL, "/etc/rc.cdrom", "multiuser", NULL };
- assumes(fwexec(rccdrom_tool, true) != -1);
+
+ /* 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);
_exit(EXIT_FAILURE);
} else if (is_netboot()) {
const char *rcnetboot_tool[] = { _PATH_BSHELL, "/etc/rc.netboot", "init", NULL };
- if (!assumes(fwexec(rcnetboot_tool, true) != -1)) {
+ if (!assumes(fwexec(rcnetboot_tool, NULL) != -1)) {
assumes(reboot(RB_HALT) != -1);
_exit(EXIT_FAILURE);
}
if (path_check("/etc/rc.server")) {
const char *rcserver_tool[] = { _PATH_BSHELL, "/etc/rc.server", NULL };
- assumes(fwexec(rcserver_tool, true) != -1);
+ assumes(fwexec(rcserver_tool, NULL) != -1);
}
-
+
read_launchd_conf();
+ handle_system_bootstrapper_crashes_separately();
if (path_check("/var/account/acct")) {
assumes(acct("/var/account/acct") != -1);
#if !TARGET_OS_EMBEDDED
if (path_check("/etc/fstab")) {
const char *mount_tool[] = { "mount", "-vat", "nonfs", NULL };
- assumes(fwexec(mount_tool, true) != -1);
+ 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 };
- assumes(fwexec(rccleanup_tool, true) != -1);
+ assumes(fwexec(rccleanup_tool, NULL) != -1);
}
+ if( path_check("/etc/rc.deferred_install") ) {
+ 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 ) {
+ 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);
+ 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);
+ }
+ }
+ }
+
empty_dir(_PATH_VARRUN, NULL);
empty_dir(_PATH_TMP, NULL);
remove(_PATH_NOLOGIN);
if (path_check("/usr/libexec/dirhelper")) {
const char *dirhelper_tool[] = { "/usr/libexec/dirhelper", "-machineBoot", NULL };
- assumes(fwexec(dirhelper_tool, true) != -1);
+ assumes(fwexec(dirhelper_tool, NULL) != -1);
}
assumes(touch_file(_PATH_UTMPX, DEFFILEMODE) != -1);
+#if !TARGET_OS_EMBEDDED
assumes(touch_file(_PATH_VARRUN "/.systemStarterRunning", DEFFILEMODE) != -1);
+#endif
+#if HAVE_LIBAUDITD
+ /*
+ * Only start auditing if not "Disabled" in auditd plist.
+ */
+ if ((lda = read_plist_file(AUDITD_PLIST_FILE, false, false)) != NULL &&
+ ((ldb = launch_data_dict_lookup(lda, LAUNCH_JOBKEY_DISABLED)) == NULL ||
+ job_disabled_logic(ldb) == false))
+ {
+ 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 };
- assumes(fwexec(audit_tool, true) != -1);
+ assumes(fwexec(audit_tool, NULL) != -1);
}
+#endif
do_BootCache_magic(BOOTCACHE_START);
_vproc_set_global_on_demand(true);
- char *load_launchd_items[] = { "load", "-D", "all", "/etc/mach_init.d",
-#if TARGET_OS_EMBEDDED
- "/var/mobile/Library/LaunchAgents",
-#endif
- NULL };
+ char *load_launchd_items[] = { "load", "-D", "all", "/etc/mach_init.d", NULL };
+ int load_launchd_items_cnt = 4;
if (is_safeboot()) {
load_launchd_items[2] = "system";
}
- assumes(load_and_unload_cmd(4, load_launchd_items) == 0);
+ assumes(load_and_unload_cmd(load_launchd_items_cnt, load_launchd_items) == 0);
/*
* 5066316
* I want a plist defined knob for jobs to give advisory hints that
* will "hopefully" serialize bootstrap. Reasons for doing so include
* pragmatic performance optimizations and attempts to workaround bugs
- * in jobs. My current thought is something like what follows.
+ * in jobs. Something like what follows might work:
*
* The BootCache would switch to launchd and add this to the plist:
*
* fine. Remember: IPC is the preferred way to serialize operations.
*
*/
- mach_timespec_t w = { 5, 0 };
- IOKitWaitQuiet(kIOMasterPortDefault, &w);
+ if (!do_apple_internal_magic) {
+ mach_timespec_t w = { 5, 0 };
+ IOKitWaitQuiet(kIOMasterPortDefault, &w);
+ }
do_BootCache_magic(BOOTCACHE_TAG);
return;
}
- fwexec(bcc_tool, true);
+ fwexec(bcc_tool, NULL);
}
int
}
if (strcasecmp(session_type, "System") == 0) {
+ bootstrapping_system = true;
system_specific_bootstrap(sflag);
} else {
- char *load_launchd_items[] = { "load", "-S", session_type, "-D", "all", NULL, NULL, NULL, NULL };
+ char *load_launchd_items[] = { "load", "-S", session_type, "-D", "all", NULL, NULL, NULL, NULL, NULL, NULL };
int the_argc = 5;
+ char *load_launchd_items_user[] = { "load", "-S", VPROCMGR_SESSION_BACKGROUND, "-D", "user", NULL };
+ int the_argc_user = 0;
+
if (is_safeboot()) {
load_launchd_items[4] = "system";
}
-
+
if (strcasecmp(session_type, VPROCMGR_SESSION_BACKGROUND) == 0 || strcasecmp(session_type, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
load_launchd_items[4] = "system";
if (!is_safeboot()) {
} else if (strcasecmp(session_type, VPROCMGR_SESSION_AQUA) == 0) {
load_launchd_items[5] = "/etc/mach_init_per_user.d";
the_argc += 1;
+ /* For now, we'll just load user Background agents when
+ * bootstrapping the Aqua session. This way, we can
+ * safely assume that the home directory is present. If
+ * we try reading the user's Background agents when we're
+ * actually bootstrapping the Background session, we run the
+ * risk of deadlocking against mount_url. But this fix should
+ * satisfy <rdar://problem/5279345>.
+ */
+ the_argc_user = 5;
+
+ /* We want to read environment.plist, which is in the user's home directory.
+ * Since the dance to mount a network home directory is fairly complex, all we
+ * can do is try and read environment.plist when bootstrapping the Aqua session,
+ * which is when we assume the home directory is present.
+ *
+ * The drawback here is that jobs bootstrapped in the Background session won't
+ * get the new environment until they quit and relaunch. But then again, they
+ * won't get the updated HOME directory or anything either. This is just a messy
+ * problem.
+ */
+ read_environment_dot_plist();
}
if (strcasecmp(session_type, VPROCMGR_SESSION_BACKGROUND) == 0) {
+ bootstrapping_peruser = true;
read_launchd_conf();
-#if HAVE_SECURITY
+#if 0 /* XXX PR-6456403 */
assumes(SessionCreate(sessionKeepCurrentBootstrap, 0) == 0);
#endif
}
- return load_and_unload_cmd(the_argc, load_launchd_items);
+ int retval = load_and_unload_cmd(the_argc, load_launchd_items);
+ 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);
+ if( !err ) {
+ retval = load_and_unload_cmd(the_argc_user, load_launchd_items_user);
+ }
+ }
+
+ return retval;
}
return 0;
return 1;
}
+ int dbfd = -1;
+ char *db = NULL;
+ vproc_err_t verr = vproc_swap_string(NULL, VPROC_GSK_JOB_OVERRIDES_DB, NULL, &db);
+ if( verr ) {
+ fprintf(stderr, "Could not get location of job overrides database.\n");
+ g_job_overrides_db_path[0] = 0;
+ } else {
+ strncpy(g_job_overrides_db_path, db, strlen(db));
+
+ /* 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 ) {
+ g_job_overrides_db = (CFMutableDictionaryRef)CreateMyPropertyListFromFile(g_job_overrides_db_path);
+ if( !g_job_overrides_db ) {
+ g_job_overrides_db = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ }
+ }
+ free(db);
+ }
+
/* I wish I didn't need to do three passes, but I need to load mDNSResponder and use it too.
* And loading legacy mach init jobs is extra fun.
*
}
}
+ if( g_job_overrides_db_has_changed ) {
+ WriteMyPropertyListToFile(g_job_overrides_db, g_job_overrides_db_path);
+ }
+
+ flock(dbfd, LOCK_UN);
+ close(dbfd);
return 0;
}
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(): %d\n", getprogname(), kr);
+ fprintf(stderr, "%s: bootstrap_create_server(): %s\n", getprogname(), bootstrap_strerror(kr));
continue;
}
- if ((kr = bootstrap_create_service(msr, (char*)sn, &msv)) != KERN_SUCCESS) {
- fprintf(stderr, "%s: bootstrap_create_service(): %d\n", getprogname(), kr);
- mach_port_destroy(mach_task_self(), msr);
+ 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);
case ESRCH:
fprintf(stderr, "%s: %s\n", lab4job, "Not loaded");
break;
+ case ENEEDAUTH:
+ fprintf(stderr, "%s: %s\n", lab4job, "Could not set security session");
default:
fprintf(stderr, "%s: %s\n", lab4job, strerror(e));
case 0:
int
list_cmd(int argc, char *const argv[])
{
- launch_data_t resp, msg;
+ launch_data_t resp, msg = NULL;
int r = 0;
- if (argc > 2) {
- fprintf(stderr, "usage: %s list [label]\n", getprogname());
+ bool plist_output = false;
+ char *label = NULL;
+ 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];
+ }
+
+ if( label ) {
msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
- launch_data_dict_insert(msg, launch_data_new_string(argv[1]), LAUNCH_KEY_GETJOB);
- } else if (vproc_swap_complex(NULL, VPROC_GSK_ALLJOBS, NULL, &resp) == NULL) {
+ launch_data_dict_insert(msg, launch_data_new_string(label), LAUNCH_KEY_GETJOB);
+
+ resp = launch_msg(msg);
+ launch_data_free(msg);
+
+ if (resp == NULL) {
+ fprintf(stderr, "launch_msg(): %s\n", strerror(errno));
+ r = 1;
+ } else if (launch_data_get_type(resp) == LAUNCH_DATA_DICTIONARY) {
+ if( plist_output ) {
+ CFDictionaryRef respDict = CFDictionaryCreateFromLaunchDictionary(resp);
+ CFStringRef plistStr = NULL;
+ if( respDict ) {
+ CFDataRef plistData = CFPropertyListCreateXMLData(NULL, (CFPropertyListRef)respDict);
+ CFRelease(respDict);
+ if( plistData ) {
+ plistStr = CFStringCreateWithBytes(NULL, CFDataGetBytePtr(plistData), CFDataGetLength(plistData), kCFStringEncodingUTF8, false);
+ CFRelease(plistData);
+ } else {
+ r = 1;
+ }
+ } else {
+ r = 1;
+ }
+
+ if( plistStr ) {
+ CFShow(plistStr);
+ CFRelease(plistStr);
+ r = 0;
+ }
+ } else {
+ print_obj(resp, NULL, NULL);
+ r = 0;
+ }
+ launch_data_free(resp);
+ } else {
+ fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]);
+ r = 1;
+ launch_data_free(resp);
+ }
+ } 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);
- return 0;
- } else {
- return 1;
- }
-
- resp = launch_msg(msg);
- launch_data_free(msg);
-
- if (resp == NULL) {
- fprintf(stderr, "launch_msg(): %s\n", strerror(errno));
- return 1;
- } else if (launch_data_get_type(resp) == LAUNCH_DATA_DICTIONARY) {
- print_obj(resp, NULL, NULL);
- } else {
- fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]);
- r = 1;
+
+ r = 0;
}
- launch_data_free(resp);
-
return r;
}
logupdate_cmd(int argc, char *const argv[])
{
int64_t inval, outval;
- int i, j, m = 0;
bool badargs = false, maskmode = false, onlymode = false, levelmode = false;
static const struct {
const char *name;
{ "alert", LOG_ALERT },
{ "emergency", LOG_EMERG },
};
- int logtblsz = sizeof logtbl / sizeof logtbl[0];
+ size_t i, j, logtblsz = sizeof logtbl / sizeof logtbl[0];
+ int m = 0;
if (argc >= 2) {
if (!strcmp(argv[1], "mask"))
m = LOG_UPTO(LOG_DEBUG);
if (argc > 2 && (maskmode || onlymode)) {
- for (i = 2; i < argc; i++) {
+ for (i = 2; i < (size_t)argc; i++) {
for (j = 0; j < logtblsz; j++) {
if (!strcmp(argv[i], logtbl[j].name)) {
if (maskmode)
}
int
-limit_cmd(int argc __attribute__((unused)), char *const argv[])
+limit_cmd(int argc, char *const argv[])
{
char slimstr[100];
char hlimstr[100];
for (i = 0; i < (lsz / sizeof(struct rlimit)); i++) {
if (argc == 2 && (size_t)which != i)
continue;
- fprintf(stdout, "\t%-12s%-15s%-15s\n", num2name(i),
+ fprintf(stdout, "\t%-12s%-15s%-15s\n", num2name((int)i),
lim2str(lmts[i].rlim_cur, slimstr),
lim2str(lmts[i].rlim_max, hlimstr));
}
lmts[which].rlim_cur = slim;
lmts[which].rlim_max = hlim;
+ bool maxfiles_exceeded = false;
+ if( strncmp(argv[1], "maxfiles", sizeof("maxfiles")) == 0 ) {
+ if( argc > 2 ) {
+ maxfiles_exceeded = ( strncmp(argv[2], "unlimited", sizeof("unlimited")) == 0 );
+ }
+
+ if( argc > 3 ) {
+ maxfiles_exceeded = ( maxfiles_exceeded || strncmp(argv[3], "unlimited", sizeof("unlimited")) == 0 );
+ }
+
+ 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;
+ }
+ }
+
msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
tmp = launch_data_new_opaque(lmts, lsz);
launch_data_dict_insert(msg, tmp, LAUNCH_KEY_SETRESOURCELIMITS);
}
}
+void
+setup_system_context(void)
+{
+ if( geteuid() != 0 ) {
+ fprintf(stderr, "You must be the root user to perform this operation.\n");
+ return;
+ }
+
+ /* Use the system launchd's socket. */
+ setenv("__USE_SYSTEM_LAUNCHD", "1", 0);
+
+ /* Put ourselves in the system launchd's bootstrap. */
+ mach_port_t rootbs = str2bsport("/");
+ mach_port_deallocate(mach_task_self(), bootstrap_port);
+ task_set_bootstrap_port(mach_task_self(), rootbs);
+ bootstrap_port = rootbs;
+}
+
int
submit_cmd(int argc, char *const argv[])
{
return 1;
}
} while (getrootbs && last_bport != bport);
+ } else if( strcmp(s, "0") == 0 || strcmp(s, "NULL") == 0 ) {
+ bport = MACH_PORT_NULL;
} else {
int pid = atoi(s);
setgid(getgid());
setuid(getuid());
- if (fwexec((const char *const *)argv + 2, true) == -1) {
+ if (fwexec((const char *const *)argv + 2, NULL) == -1) {
fprintf(stderr, "%s bsexec failed: %s\n", getprogname(), strerror(errno));
return 1;
}
}
int
-bslist_cmd(int argc, char *const argv[])
+_bslist_cmd(mach_port_t bport, unsigned int depth, bool show_job, bool local_only)
{
kern_return_t result;
- mach_port_t bport = bootstrap_port;
name_array_t service_names;
- mach_msg_type_number_t service_cnt, service_active_cnt;
+ name_array_t service_jobs;
+ mach_msg_type_number_t service_cnt, service_jobs_cnt, service_active_cnt;
bootstrap_status_array_t service_actives;
unsigned int i;
-
- if (argc == 2)
- bport = str2bsport(argv[1]);
-
+
if (bport == MACH_PORT_NULL) {
fprintf(stderr, "Invalid bootstrap port\n");
return 1;
}
-
- result = bootstrap_info(bport, &service_names, &service_cnt, &service_actives, &service_active_cnt);
+
+ uint64_t flags = 0;
+ flags |= local_only ? BOOTSTRAP_FORCE_LOCAL : 0;
+ result = bootstrap_info(bport, &service_names, &service_cnt, &service_jobs, &service_jobs_cnt, &service_actives, &service_active_cnt, flags);
if (result != BOOTSTRAP_SUCCESS) {
fprintf(stderr, "bootstrap_info(): %d\n", result);
return 1;
}
-
+
#define bport_state(x) (((x) == BOOTSTRAP_STATUS_ACTIVE) ? "A" : ((x) == BOOTSTRAP_STATUS_ON_DEMAND) ? "D" : "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 ) {
+ fprintf(stdout, " (%s)", service_jobs[i]);
+ }
+ fprintf(stdout, "\n");
+ }
+
+ return 0;
+}
- for (i = 0; i < service_cnt ; i++)
- fprintf(stdout, "%-3s%s\n", bport_state((service_actives[i])), service_names[i]);
+int
+bslist_cmd(int argc, char *const argv[])
+{
+ mach_port_t bport = bootstrap_port;
+ bool show_jobs = false;
+ if( argc > 2 && strcmp(argv[2], "-j") == 0 ) {
+ show_jobs = true;
+ }
+
+ if( argc > 1 ) {
+ if( show_jobs ) {
+ bport = str2bsport(argv[1]);
+ } else if( strcmp(argv[1], "-j") == 0 ) {
+ show_jobs = true;
+ }
+ }
+
+ if( bport == MACH_PORT_NULL ) {
+ fprintf(stderr, "Invalid bootstrap port\n");
+ return 1;
+ }
+
+ return _bslist_cmd(bport, 0, show_jobs, false);
+}
+
+int
+_bstree_cmd(mach_port_t bsport, unsigned int depth, bool show_jobs)
+{
+ if( bsport == MACH_PORT_NULL ) {
+ fprintf(stderr, "No root port!\n");
+ return 1;
+ }
+
+ mach_port_array_t child_ports = NULL;
+ name_array_t child_names = NULL;
+ bootstrap_property_array_t child_props = NULL;
+ 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 ) {
+ fprintf(stderr, "You must be root to perform this operation.\n");
+ } else {
+ fprintf(stderr, "bootstrap_lookup_children(): %d\n", kr);
+ }
+ return 1;
+ }
+
+ unsigned int i = 0;
+ _bslist_cmd(bsport, depth, show_jobs, true);
+
+ for( i = 0; i < cnt; i++ ) {
+ char *type = NULL;
+ if( child_props[i] & BOOTSTRAP_PROPERTY_PERUSER ) {
+ type = "Per-user";
+ } else if( child_props[i] & BOOTSTRAP_PROPERTY_EXPLICITSUBSET ) {
+ type = "Explicit Subset";
+ } else if( child_props[i] & BOOTSTRAP_PROPERTY_IMPLICITSUBSET ) {
+ type = "Implicit Subset";
+ } else if( child_props[i] & BOOTSTRAP_PROPERTY_MOVEDSUBSET ) {
+ type = "Moved Subset";
+ }
+
+ fprintf(stdout, "%*s%s (%s)/\n", depth, "", child_names[i], type);
+ if( child_ports[i] != MACH_PORT_NULL ) {
+ _bstree_cmd(child_ports[i], depth + 4, show_jobs);
+ }
+ }
+
+ return 0;
+}
+
+int
+bstree_cmd(int argc, char * const argv[])
+{
+ bool show_jobs = false;
+ if( geteuid() != 0 ) {
+ fprintf(stderr, "You must be root to perform this operation.\n");
+ return 1;
+ } else {
+ if( argc == 2 && strcmp(argv[1], "-j") == 0 ) {
+ show_jobs = true;
+ }
+ fprintf(stdout, "System/\n");
+ }
+
+ return _bstree_cmd(str2bsport("/"), 4, show_jobs);
+}
+
+int
+managerpid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused)))
+{
+ int64_t manager_pid = 0;
+ vproc_err_t verr = vproc_swap_integer(NULL, VPROC_GSK_MGR_PID, NULL, (int64_t *)&manager_pid);
+ if( verr ) {
+ fprintf(stdout, "Unknown job manager!\n");
+ return 1;
+ }
+
+ fprintf(stdout, "%d\n", (pid_t)manager_pid);
+ return 0;
+}
+
+int
+manageruid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused)))
+{
+ int64_t manager_uid = 0;
+ vproc_err_t verr = vproc_swap_integer(NULL, VPROC_GSK_MGR_UID, NULL, (int64_t *)&manager_uid);
+ if( verr ) {
+ fprintf(stdout, "Unknown job manager!\n");
+ return 1;
+ }
+
+ fprintf(stdout, "%lli\n", manager_uid);
+ return 0;
+}
+
+int
+managername_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused)))
+{
+ char *manager_name = NULL;
+ vproc_err_t verr = vproc_swap_string(NULL, VPROC_GSK_MGR_NAME, NULL, &manager_name);
+ if( verr ) {
+ fprintf(stdout, "Unknown job manager!\n");
+ return 1;
+ }
+
+ fprintf(stdout, "%s\n", manager_name);
+ free(manager_name);
+
return 0;
}
}
pid_t
-fwexec(const char *const *argv, bool _wait)
+fwexec(const char *const *argv, int *wstatus)
{
- int wstatus;
+ int wstatus2;
pid_t p;
- switch ((p = fork())) {
- case -1:
- break;
- case 0:
- if (!_wait) {
- setsid();
- }
+ /* We'd use posix_spawnp(), but we want to workaround: 6288899 */
+
+ if ((p = vfork()) == -1) {
+ return -1;
+ } else if (p == 0) {
execvp(argv[0], (char *const *)argv);
_exit(EXIT_FAILURE);
- break;
- default:
- if (!_wait)
- return p;
- if (p == waitpid(p, &wstatus, 0)) {
- if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == EXIT_SUCCESS)
- return p;
- }
- break;
+ }
+
+ if (waitpid(p, wstatus ? wstatus : &wstatus2, 0) == -1) {
+ return -1;
+ }
+
+ if (wstatus) {
+ return p;
+ } else if (WIFEXITED(wstatus2) && WEXITSTATUS(wstatus2) == EXIT_SUCCESS) {
+ return p;
}
return -1;
goto out;
}
#endif
-
- if (fwexec(fsck_tool, true) != -1) {
+ fprintf(stdout, "Running fsck on the boot volume...\n");
+ if (fwexec(fsck_tool, NULL) != -1) {
goto out;
}
}
- if (fwexec(safe_fsck_tool, true) != -1) {
+ if (fwexec(safe_fsck_tool, NULL) != -1) {
goto out;
}
- fprintf(stderr, "fsck failed!\n");
+ fprintf(stdout, "fsck failed!\n");
/* someday, we should keep booting read-only, but as of today, other sub-systems cannot handle that scenario */
-#if TARGET_OS_EMBEDDED
- const char *nvram_tool[] = { "/usr/sbin/nvram", "auto-boot=false", NULL };
- assumes(fwexec(nvram_tool, true) != -1);
- assumes(reboot(RB_AUTOBOOT) != -1);
-#else
assumes(reboot(RB_HALT) != -1);
-#endif
return;
out:
*
* assumes(mount(sfs.f_fstypename, "/", MNT_UPDATE, NULL) != -1);
*/
-
#if TARGET_OS_EMBEDDED
if (path_check("/etc/fstab")) {
const char *mount_tool[] = { "mount", "-vat", "nonfs", NULL };
- if (!assumes(fwexec(mount_tool, true) != -1)) {
- assumes(fwexec(nvram_tool, true) != -1);
- assumes(reboot(RB_AUTOBOOT) != -1);
- }
+ assumes(fwexec(mount_tool, NULL) != -1);
} else
#endif
{
- assumes(fwexec(remount_tool, true) != -1);
+ assumes(fwexec(remount_tool, NULL) != -1);
}
fix_bogus_file_metadata();
const gid_t group;
const mode_t needed_bits;
const mode_t bad_bits;
+ const bool create;
} f[] = {
- { "/sbin/launchd", 0, 0, S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, S_ISUID|S_ISGID|S_ISVTX|S_IWOTH },
- { _PATH_TMP, 0, 0, S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO, S_ISUID|S_ISGID },
- { _PATH_VARTMP, 0, 0, S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO, S_ISUID|S_ISGID },
+ { "/sbin/launchd", 0, 0, S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, S_ISUID|S_ISGID|S_ISVTX|S_IWOTH, false },
+ { _PATH_TMP, 0, 0, S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO, S_ISUID|S_ISGID, 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 }
};
struct stat sb;
size_t i;
bool fix_id = false;
if (!assumes(stat(f[i].path, &sb) != -1)) {
- continue;
+ 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) ) {
+ continue;
+ } else if( !assumes(stat(f[i].path, &sb) != -1) ) {
+ continue;
+ }
+ } else {
+ continue;
+ }
}
i_needed_bits = ~sb.st_mode & f[i].needed_bits;
}
}
+
bool
path_check(const char *path)
{
goto skip_sysctl_tool;
}
sysctl_tool[2] = val;
- assumes(fwexec(sysctl_tool, true) != -1);
+ assumes(fwexec(sysctl_tool, NULL) != -1);
skip_sysctl_tool:
free(tmpstr);
}
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, strlen(prog) + 1) != -1 || errno == ENOPROTOOPT);
+ assumes(setsockopt(sfd, SOL_SOCKET, SO_EXECPATH, prog, (socklen_t)(strlen(prog) + 1)) != -1 || errno == ENOPROTOOPT);
}
}
CFRelease(bootrootProp);
- if (!assumes((p = fwexec(kextcache_tool, false)) != -1)) {
- return;
- }
-
- if (!assumes(waitpid(p, &wstatus, 0) != -1)) {
+ if (!assumes((p = fwexec(kextcache_tool, &wstatus)) != -1)) {
return;
}
assumes(reboot(RB_AUTOBOOT) != -1);
}
}
+
+void
+do_file_init(void)
+{
+ struct stat sb;
+
+ if (stat("/AppleInternal", &sb) == 0 && stat("/var/db/disableAppleInternal", &sb) == -1) {
+ do_apple_internal_magic = true;
+ }
+
+ char bootargs[128];
+ size_t len = sizeof(bootargs) - 1;
+ 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 ) {
+ g_verbose_boot = true;
+ }
+}
-.Dd September 30, 2004
+.Dd 1 May, 2009
.Dt launchd 8
.Os Darwin
.Sh NAME
Where possible, it is preferable for jobs to launch on demand based on criteria specified
in their respective configuration files.
.Pp
-When run with a command, a specific instance of
-.Nm
-is created and the command is implicitly added to the list of jobs maintained by
-.Nm .
-If the command exits, that instance of
-.Nm
-will clean up all jobs maintained by itself and exit. All children of the command will use that
-instance of
-.Nm .
-.Pp
During boot
.Nm
is invoked by the kernel to run as the first process on the system and to further bootstrap the rest of the system.
-.Sh OPTIONS
-.Bl -tag -width -indent
-.It Fl D
-Debug. Prints syslog messages to stderr and adjusts logging via
-.Xr syslog 3
-to LOG_DEBUG.
-.El
-.Sh OPTIONS WHEN RUN AS PID 1
-.Bl -tag -width -indent
-.It Fl s
-Single user mode. Instructs
-.Nm launchd
-to give a shell prompt before booting the system.
-.El
+.Pp
+You cannot invoke
+.Nm
+directly.
.Sh ENVIRONMENTAL VARIABLES
.Bl -tag -width -indent
.It Pa LAUNCHD_SOCKET
This variable is exported when invoking a command via the launchd command line. It informs launchctl how to find the correct launchd to talk to.
.El
.Sh NOTES
-In Darwin it is preferable to have your daemon launch via launchd instead of modifying
-.Nm rc
-or creating a
-.Nm SystemStarter
-Startup Item.
+In Darwin, the canonical way to launch a daemon is through
+.Nm launchd
+as opposed to more traditional mechanisms or mechanisms provided in earlier versions of Mac OS X. These alternate methods should
+be considered deprecated and not suitable for new projects.
.Pp
-At some point in the future, we hope to completely phase out the use of
-.Nm rc .
+In the
+.Nm launchd
+lexicon, a "daemon" is, by definition, a system-wide service of which there is one instance for all clients. An "agent" is a service that runs on
+a per-user basis. Daemons should not attempt to display UI or interact directly with a user's login session. Any and all work that involves interacting
+with a user should be done through agents.
+.Pp
+If you wish your service to run as a certain user, in that user's environment, making it a
+.Nm launchd
+agent is the ONLY supported means of accomplishing this on Mac OS X. In other words, it is not sufficient to perform a
+.Xr setuid 2
+to become a user in the truest sense on Mac OS X.
.Sh FILES
.Bl -tag -width "/System/Library/LaunchDaemons" -compact
.It Pa ~/Library/LaunchAgents
.It Pa /Library/LaunchAgents
Per-user agents provided by the administrator.
.It Pa /Library/LaunchDaemons
-System wide daemons provided by the administrator.
+System-wide daemons provided by the administrator.
.It Pa /System/Library/LaunchAgents
-Mac OS X Per-user agents.
+Per-user agents provided by Mac OS X.
.It Pa /System/Library/LaunchDaemons
-Mac OS X System wide daemons.
+System-wide daemons provided by Mac OS X.
.El
.Sh SEE ALSO
.Xr launchctl 1 ,
.Xr launchd.plist 5 ,
-.Xr rc 8 ,
-.Xr SystemStarter 8
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
-static const char *const __rcs_file_version__ = "$Revision: 23748 $";
+static const char *const __rcs_file_version__ = "$Revision: 23925 $";
#include "config.h"
#include "launchd.h"
#include <sys/mount.h>
#include <sys/kern_event.h>
#include <sys/reboot.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <setjmp.h>
#include <spawn.h>
#include <sched.h>
-#if TARGET_OS_EMBEDDED
#include <pthread.h>
+#include <util.h>
+
+#if HAVE_LIBAUDITD
+#include <bsm/auditd_lib.h>
#endif
#include "bootstrap.h"
#include "vproc.h"
+#include "vproc_priv.h"
#include "vproc_internal.h"
#include "launch.h"
+#include "launch_internal.h"
#include "launchd_runtime.h"
#include "launchd_core_logic.h"
#define LAUNCHD_CONF ".launchd.conf"
#define SECURITY_LIB "/System/Library/Frameworks/Security.framework/Versions/A/Security"
-#define SHUTDOWN_LOG_DIR "/var/log/shutdown"
-
extern char **environ;
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 prep_shutdown_log_dir(void);
+static void do_pid1_crash_diagnosis_mode(void);
+static int basic_fork(void);
+static bool do_pid1_crash_diagnosis_mode2(void);
-#if TARGET_OS_EMBEDDED
static void *update_thread(void *nothing);
-#endif
-static bool re_exec_in_single_user_mode = false;
+static bool re_exec_in_single_user_mode;
static void *crash_addr;
static pid_t crash_pid;
-#if TARGET_OS_EMBEDDED
-static unsigned int g_sync_frequency = 30;
-#endif
-
-static bool shutdown_in_progress = false;
-bool debug_shutdown_hangs = false;
-bool network_up = false;
+bool shutdown_in_progress;
+bool fake_shutdown_in_progress;
+bool network_up;
+char g_username[128] = "__Uninitialized__";
+char g_my_label[128] = "__Uninitialized__";
+char g_launchd_database_dir[PATH_MAX];
+FILE *g_console = NULL;
+int32_t g_sync_frequency = 30;
int
main(int argc, char *const *argv)
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 (!getenv("DYLD_INSERT_LIBRARIES")) {
+ setenv("DYLD_INSERT_LIBRARIES", "/usr/lib/libgmalloc.dylib", 1);
+ setenv("MALLOC_STRICT_SIZE", "1", 1);
+ execv(argv[0], argv);
+ } else {
+ unsetenv("DYLD_INSERT_LIBRARIES");
+ unsetenv("MALLOC_STRICT_SIZE");
+ }
+ }
+
while ((ch = getopt(argc, argv, "s")) != -1) {
switch (ch) {
case 's': sflag = true; break; /* single user */
launchd_runtime_init();
+ if( pid1_magic ) {
+ int cfd = -1;
+ if( launchd_assumes((cfd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) != -1) ) {
+ _fd(cfd);
+ if( !launchd_assumes((g_console = fdopen(cfd, "w")) != NULL) ) {
+ close(cfd);
+ }
+ }
+ }
+
if (NULL == getenv("PATH")) {
setenv("PATH", _PATH_STDPATH, 1);
}
- if (getpid() == 1) {
+ if (pid1_magic) {
pid1_magic_init();
} else {
ipc_server_init();
+
+ runtime_log_push();
+
+ struct passwd *pwent = getpwuid(getuid());
+ if( pwent ) {
+ strlcpy(g_username, pwent->pw_name, sizeof(g_username) - 1);
+ }
+
+ snprintf(g_my_label, sizeof(g_my_label), "com.apple.launchd.peruser.%u", getuid());
+
+ auditinfo_addr_t auinfo;
+ if( launchd_assumes(getaudit_addr(&auinfo, sizeof(auinfo)) != -1) ) {
+ g_audit_session = auinfo.ai_asid;
+ runtime_syslog(LOG_DEBUG, "Our audit session ID is %i", g_audit_session);
+ }
+
+ g_audit_session_port = _audit_session_self();
+ snprintf(g_launchd_database_dir, sizeof(g_launchd_database_dir), LAUNCHD_DB_PREFIX "/com.apple.launchd.peruser.%u", getuid());
+ runtime_syslog(LOG_DEBUG, "Per-user launchd for UID %u (%s) has begun.", getuid(), g_username);
}
-#if TARGET_OS_EMBEDDED
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
-
- if( getpid() == 1 ) {
- /* Start the update thread -- rdar://problem/5039559&6153301 */
- pthread_t t = NULL;
- int err = pthread_create(&t, &attr, update_thread, NULL);
- launchd_assumes(err == 0);
+ if( pid1_magic ) {
+ runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** launchd[1] has started up. ***");
+ if( g_use_gmalloc ) {
+ runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Using libgmalloc ***");
+ }
+
+ if( g_verbose_boot ) {
+ runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Verbose boot, will log to /dev/console. ***");
+ }
+
+ 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;
}
-#endif
-
+
monitor_networking_state();
- if (getpid() == 1) {
+ if (pid1_magic) {
handle_pid1_crashes_separately();
+ } else {
+ #if !TARGET_OS_EMBEDDED
+ /* prime shared memory before the 'bootstrap_port' global is set to zero */
+ _vproc_transaction_begin();
+ _vproc_transaction_end();
+ #endif
}
- jobmgr_init(sflag);
+ if( pid1_magic ) {
+ /* 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);
+ }
+ jobmgr_init(sflag);
+
launchd_runtime_init2();
launchd_runtime();
launchd_assumes(sigaction(SIGSEGV, &fsa, NULL) != -1);
}
+void *update_thread(void *nothing __attribute__((unused)))
+{
+ while( g_sync_frequency ) {
+ sync();
+ sleep(g_sync_frequency);
+ }
+
+ runtime_syslog(LOG_DEBUG, "Update thread exiting.");
+ return NULL;
+}
+
#define PID1_CRASH_LOGFILE "/var/log/launchd-pid1.crash"
/* This hack forces the dynamic linker to resolve these symbols ASAP */
static __attribute__((unused)) typeof(sleep) *__junk_dyld_trick2 = sleep;
static __attribute__((unused)) typeof(reboot) *__junk_dyld_trick3 = reboot;
+void
+do_pid1_crash_diagnosis_mode(void)
+{
+ if( g_wsp ) {
+ kill(g_wsp, SIGKILL);
+ sleep(3);
+ g_wsp = 0;
+ }
+
+ while( g_shutdown_debugging && !do_pid1_crash_diagnosis_mode2() ) {
+ sleep(1);
+ }
+}
+
+int
+basic_fork(void)
+{
+ int wstatus = 0;
+ pid_t p;
+
+ switch ((p = fork())) {
+ case -1:
+ runtime_syslog(LOG_ERR | LOG_CONSOLE, "Can't fork PID 1 copy for crash debugging: %m");
+ return p;
+ case 0:
+ return p;
+ default:
+ #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;
+ }
+
+ return -1;
+}
+
+bool
+do_pid1_crash_diagnosis_mode2(void)
+{
+ if( basic_fork() == 0 ) {
+ /* Neuter our bootstrap port so that the shell doesn't try talking to us while
+ * we're blocked waiting on it.
+ */
+ if( g_console ) {
+ fflush(g_console);
+ }
+ task_set_bootstrap_port(mach_task_self(), MACH_PORT_NULL);
+ if( basic_fork() != 0 ) {
+ if( g_console ) {
+ fflush(g_console);
+ }
+ return true;
+ }
+ } else {
+ return true;
+ }
+
+ int fd;
+ revoke(_PATH_CONSOLE);
+ if ((fd = open(_PATH_CONSOLE, O_RDWR)) == -1) {
+ _exit(2);
+ }
+ if (login_tty(fd) == -1) {
+ _exit(3);
+ }
+ setenv("TERM", "vt100", 1);
+ fprintf(stdout, "\n");
+ fprintf(stdout, "Entering launchd PID 1 debugging mode...\n");
+ fprintf(stdout, "The PID 1 launchd has crashed. It has fork(2)ed itself for debugging.\n");
+ fprintf(stdout, "To debug the main thread of PID 1:\n");
+ fprintf(stdout, " gdb attach %d\n", getppid());
+ fprintf(stdout, "To exit this shell and shut down:\n");
+ fprintf(stdout, " kill -9 1\n");
+ fprintf(stdout, "A sample of PID 1 has been written to %s\n", PID1_CRASH_LOGFILE);
+ fprintf(stdout, "\n");
+ fflush(stdout);
+
+ execl(_PATH_BSHELL, "-sh", NULL);
+ syslog(LOG_ERR, "can't exec %s for PID 1 crash debugging: %m", _PATH_BSHELL);
+ _exit(EXIT_FAILURE);
+}
+
void
fatal_signal_handler(int sig, siginfo_t *si, void *uap __attribute__((unused)))
{
crash_addr = si->si_addr;
crash_pid = si->si_pid;
-
+
unlink(PID1_CRASH_LOGFILE);
switch ((sample_p = vfork())) {
break;
}
+ do_pid1_crash_diagnosis_mode();
+
switch (sig) {
default:
case 0:
launchd_assumes(setsid() != -1);
launchd_assumes(chdir("/") != -1);
launchd_assumes(setlogin("root") != -1);
- launchd_assumes(mount("fdesc", "/dev", MNT_UNION, NULL) != -1);
+
+ strcpy(g_my_label, "com.apple.launchd");
+
+#if !TARGET_OS_EMBEDDED
+ auditinfo_addr_t auinfo = {
+ .ai_termid = { .at_type = AU_IPv4 },
+ .ai_asid = AU_ASSIGN_ASID,
+ .ai_auid = AU_DEFAUDITID,
+ .ai_flags = sessionIsRoot,
+ };
+
+ if( !launchd_assumes(setaudit_addr(&auinfo, sizeof(auinfo)) != -1) ) {
+ runtime_syslog(LOG_WARNING | LOG_CONSOLE, "Could not set audit session: %s.", strerror(errno));
+ _exit(EXIT_FAILURE);
+ }
+
+ if( launchd_assumes(getaudit_addr(&auinfo, sizeof(auinfo)) != -1) ) {
+ g_audit_session = auinfo.ai_asid;
+ runtime_syslog(LOG_DEBUG, "Our audit session ID is %i", g_audit_session);
+ }
+
+ g_audit_session_port = _audit_session_self();
+#endif
+
+ strcpy(g_launchd_database_dir, LAUNCHD_DB_PREFIX "/com.apple.launchd");
}
+char *
+launchd_data_base_path(int db_type)
+{
+ static char result[PATH_MAX];
+ static int last_db_type = -1;
+
+ if( db_type == last_db_type ) {
+ return result;
+ }
+
+ switch( db_type ) {
+ case LAUNCHD_DB_TYPE_OVERRIDES :
+ snprintf(result, sizeof(result), "%s/%s", g_launchd_database_dir, "overrides.plist");
+ last_db_type = db_type;
+ break;
+ case LAUNCHD_DB_TYPE_JOBCACHE :
+ snprintf(result, sizeof(result), "%s/%s", g_launchd_database_dir, "jobcache.launchdata");
+ last_db_type = db_type;
+ break;
+ default :
+ break;
+ }
+
+ return result;
+}
int
_fd(int fd)
return fd;
}
-void
-prep_shutdown_log_dir(void)
-{
- launchd_assumes(mkdir(SHUTDOWN_LOG_DIR, S_IRWXU) != -1 || errno == EEXIST);
-}
-
-#if TARGET_OS_EMBEDDED
-void *
-update_thread(void *nothing __attribute__((unused)))
-{
- while( g_sync_frequency ) {
- sync();
- sleep(g_sync_frequency);
- }
-
- return NULL;
-}
-#endif
-
void
launchd_shutdown(void)
{
- struct stat sb;
+ int64_t now;
if (shutdown_in_progress) {
return;
}
+ runtime_ktrace0(RTKT_LAUNCHD_EXITING);
+
shutdown_in_progress = true;
- if (getpid() == 1 && stat("/var/db/debugShutdownHangs", &sb) != -1) {
+ if( pid1_magic || g_log_per_user_shutdown ) {
/*
* When this changes to a more sustainable API, update this:
* http://howto.apple.com/db.cgi?Debugging_Apps_Non-Responsive_At_Shutdown
*/
runtime_setlogmask(LOG_UPTO(LOG_DEBUG));
- prep_shutdown_log_dir();
- debug_shutdown_hangs = true;
}
+ runtime_log_push();
+
+ now = runtime_get_wall_time();
+
+ char *term_who = pid1_magic ? "System shutdown" : "Per-user launchd termination for ";
+ runtime_syslog(LOG_INFO, "%s%s began", term_who, pid1_magic ? "" : g_username);
+
launchd_assert(jobmgr_shutdown(root_jobmgr) != NULL);
+
+#if HAVE_LIBAUDITD
+ if( pid1_magic ) {
+ launchd_assumes(audit_quick_stop() == 0);
+ }
+#endif
}
void
bool new_networking_state;
char buf[1024];
- launchd_assumes(read(kev->ident, &buf, sizeof(buf)) != -1);
+ launchd_assumes(read((int)kev->ident, &buf, sizeof(buf)) != -1);
new_networking_state = get_network_state();
const char *file = strrchr(path, '/');
char *rcs_rev_tmp = strchr(rcs_rev, ' ');
+ runtime_ktrace1(RTKT_LAUNCHD_BUG);
+
if (!file) {
file = path;
} else {
-.Dd January 10, 2005
+.Dd 1 May, 2009
.Dt launchd.conf 5
.Os Darwin
.Sh NAME
.Nm /etc/launchd.conf
.Sh DESCRIPTION
.Nm
-contains a list of subcommands to run via
-.Nm launchctl
+contains a list of subcommands
+.Ar ( load ,
+.Ar unload ,
+etc.) to run via
+.Xr launchctl 1
when
-.Nm launchd
+.Xr launchd 8
starts.
.Sh FILES
.Bl -tag -width "$HOME/.launchd.conf" -compact
.It Pa $HOME/.launchd.conf
-Your launchd configuration file.
+Your launchd configuration file (currently unsupported).
.It Pa /etc/launchd.conf
The system's launchd configuration file.
.El
#include "bootstrap.h"
#include "launchd_runtime.h"
-#define SHUTDOWN_LOG_DIR "/var/log/shutdown"
-
struct kevent;
struct conncb;
-extern bool debug_shutdown_hangs;
+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];
bool init_check_pid(pid_t);
void launchd_single_user(void);
boolean_t launchd_mach_ipc_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply);
+enum {
+ LAUNCHD_DB_TYPE_OVERRIDES,
+ LAUNCHD_DB_TYPE_JOBCACHE,
+ LAUNCHD_DB_TYPE_LAST,
+};
+char *launchd_data_base_path(int db_type);
+
void mach_start_shutdown(void);
int _fd(int fd);
--- /dev/null
+< mach* >
+ mach-per-user-lookup
-.Dd September 30, 2004
+.Dd 1 May, 2009
.Dt launchd.plist 5
.Os Darwin
.Sh NAME
Catch the SIGTERM signal.
.El
.Sh XML PROPERTY LIST KEYS
-The follow keys can be used to describe the configuration details of your daemon or agent.
+The following keys can be used to describe the configuration details of your daemon or agent.
Property lists are Apple's standard configuration file format. Please see
.Xr plist 5
-for more information. Please note. Property list files are expected to have their name end in ".plist".
+for more information. Please note: property list files are expected to have their name end in ".plist".
+Also please note that it is the expected convention for launchd property list files to be named <Label>.plist.
+Thus, if your job label is "com.apple.sshd", your plist file should be named "com.apple.sshd.plist".
.Pp
.Bl -ohang
.It Sy Label <string>
This required key uniquely identifies the job to
.Nm launchd .
.It Sy Disabled <boolean>
-This optional key is used to disable your job. The default is false.
+This optional key is used as a hint to
+.Xr launchctl 1
+that it should not submit this job to
+.Nm launchd
+when loading a job or jobs. The value of this key does NOT reflect the current state of the job on the running system. If you wish to know whether a job is loaded in launchd, reading this key from a configuration file yourself is not a
+sufficient test. You should query
+.Nm launchd
+for the presence of the job using the
+.Xr launchctl 1
+.Ar list
+subcommand or use the ServiceManagement framework's SMJobCopyDictionary() method.
+.Pp
+Note that as of Mac OS X v10.6, this key's value in a configuration
+file conveys a default value, which is changed with the
+.Op Ar -w
+option of the
+.Xr launchctl 1
+.Ar load
+and
+.Ar unload
+subcommands. These subcommands no longer modify the configuration file, so the value displayed in the configuration file is not necessarily the value that
+.Xr launchctl 1
+will apply. See
+.Xr launchctl 1
+for more information.
+.Pp
+Please also be mindful that you should only use this key if the provided
+on-demand and KeepAlive criteria are insufficient to describe the conditions under which your job needs to run. The cost
+to have a job loaded in
+.Nm launchd
+is negligible, so there is no harm in loading a job which only runs once or very rarely.
.It Sy UserName <string>
This optional key specifies the user to run the job as. This key is only applicable when launchd is running as root.
.It Sy GroupName <string>
is called on behalf of the job, and the result is passed via the standard in/out/error descriptors.
.El
.It Sy LimitLoadToHosts <array of strings>
-This configuration file only applies to the hosts listed with this key.
+This configuration file only applies to the hosts listed with this key. Note: One should set kern.hostname in
+.Xr sysctl.conf 5
+for this feature to work reliably.
.It Sy LimitLoadFromHosts <array of strings>
-This configuration file only applies to hosts NOT listed with this key.
+This configuration file only applies to hosts NOT listed with this key. Note: One should set kern.hostname in
+.Xr sysctl.conf 5
+for this feature to work reliably.
.It Sy LimitLoadToSessionType <string>
This configuration file only applies to sessions of the type specified. This key is used
in concert with the -S flag to
.It Sy ProgramArguments <array of strings>
This key maps to the second argument of
.Xr execvp 3 .
-This key is required in the absence of the Program key. Please note! Many people are confused by this key. Please read
+This key is required in the absence of the Program key. Please note: many people are confused by this key. Please read
.Xr execvp 3
very carefully!
.It Sy EnableGlobbing <boolean>
to use the
.Xr glob 3
mechanism to update the program arguments before invocation.
+.It Sy EnableTransactions <boolean>
+This flag instructs
+.Nm launchd
+that the job promises to use
+.Xr vproc_transaction_begin 3
+and
+.Xr vproc_transaction_end 3
+to track outstanding transactions that need to be reconciled before the process can safely terminate. If no outstanding transactions are in progress, then
+.Nm launchd
+is free to send the SIGKILL signal.
.It Sy OnDemand <boolean>
This key was used in Mac OS X 10.4 to control whether a job was kept alive or not. The default was true.
-This key has been deprecated and replaced in Mac OS X 10.5 with the more powerful KeepAlive option.
+This key has been deprecated and replaced in Mac OS X 10.5 and later with the more powerful KeepAlive option.
.It Sy KeepAlive <boolean or dictionary of stuff>
This optional key is used to control whether your job is to be kept
continuously running or to let demand and conditions control the invocation. The
.Xr chdir 2
to before running the job.
.It Sy EnvironmentVariables <dictionary of strings>
-This optional key is used to specify additional environmental variables to be setup before running the job.
+This optional key is used to specify additional environmental variables to be set before running the job.
.It Sy Umask <integer>
This optional key specifies what value should be passed to
.Xr umask 2
The principle behind this is that jobs should linger around just in case they are needed again in the near future. This not only
reduces the latency of responses, but it encourages developers to amortize the cost of program invocation.
.It Sy InitGroups <boolean>
-This optional key specifies whether the job should have
+This optional key specifies whether
.Xr initgroups 3
-be called before running the job.
+should be called before running the job.
The default is true in 10.5 and false in 10.4. This key will be ignored if the UserName key is not set.
.It Sy WatchPaths <array of strings>
This optional key causes the job to be started if any one of the listed paths are modified.
.It Sy Month <integer>
The month on which this job will be run.
.El
+.It Sy StandardInPath <string>
+This optional key specifies what file should be used for data being supplied to stdin when using
+.Xr stdio 3 .
.It Sy StandardOutPath <string>
This optional key specifies what file should be used for data being sent to stdout when using
.Xr stdio 3 .
function.
.It Sy NumberOfFiles <integer>
The maximum number of open files for this process.
+Setting this value in a system wide daemon will set the
+.Xr sysctl 3
+kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits) value in addition to the
+.Xr setrlimit 2
+values.
.It Sy NumberOfProcesses <integer>
The maximum number of simultaneous processes for this user id.
+Setting this value in a system wide daemon will set the
+.Xr sysctl 3
+kern.maxproc (SoftResourceLimits) or kern.maxprocperuid (HardResourceLimits)
+value in addition to the
+.Xr setrlimit 2
+values.
.It Sy ResidentSetSize <integer>
The maximum size (in bytes) to which a process's resident set size may grow.
This imposes a limit on the amount of physical memory to be given to a process;
know when to run the job. The job must check-in to get a copy of the file descriptors using APIs outlined in
.Xr launch 3 .
The keys of the top level Sockets dictionary can be anything. They are meant for the application developer to use to
-differentiate different which descriptors correspond to which application level protocols (e.g. http vs. ftp vs. DNS...).
-At check in time, the value of each Sockets dictionary key will be an array of descriptors. Daemon/Agent writers should
+differentiate which descriptors correspond to which application level protocols (e.g. http vs. ftp vs. DNS...).
+At check-in time, the value of each Sockets dictionary key will be an array of descriptors. Daemon/Agent writers should
consider all descriptors of a given key to be to be effectively equivalent, even though each file descriptor likely represents
a different networking protocol which conforms to the criteria specified in the job configuration file.
.Pp
.It Pa /Library/LaunchAgents
Per-user agents provided by the administrator.
.It Pa /Library/LaunchDaemons
-System wide daemons provided by the administrator.
+System-wide daemons provided by the administrator.
.It Pa /System/Library/LaunchAgents
-Mac OS X Per-user agents.
+Per-user agents provided by Mac OS X.
.It Pa /System/Library/LaunchDaemons
-Mac OS X System wide daemons.
+System-wide daemons provided by Mac OS X.
.El
.Sh SEE ALSO
.Xr launchctl 1 ,
-.Xr launch 3 ,
+.Xr sysctl 3 ,
.Xr launchd 8 ,
.Xr plist 5
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
-static const char *const __rcs_file_version__ = "$Revision: 23923 $";
+static const char *const __rcs_file_version__ = "$Revision: 23932 $";
#include "config.h"
#include "launchd_core_logic.h"
#include <TargetConditionals.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
-#include <mach/mach_time.h>
#include <mach/boolean.h>
#include <mach/message.h>
#include <mach/notify.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/pipe.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <ctype.h>
#include <glob.h>
#include <spawn.h>
+#include <libproc.h>
+#include <malloc/malloc.h>
+#include <pthread.h>
#if HAVE_SANDBOX
+#define __APPLE_API_PRIVATE
#include <sandbox.h>
#endif
#if HAVE_QUARANTINE
#include <quarantine.h>
#endif
+#if TARGET_OS_EMBEDDED
+#include <sys/kern_memorystatus.h>
+#else
+/* To make my life easier. */
+typedef struct jetsam_priority_entry {
+ pid_t pid;
+ uint32_t flags;
+} jetsam_priority_entry_t;
+
+enum {
+ kJetsamFlagsFrontmost = (1 << 0),
+ kJetsamFlagsKilled = (1 << 1)
+};
+#endif
#include "launch.h"
#include "launch_priv.h"
#include "protocol_vproc.h"
#include "protocol_vprocServer.h"
#include "protocol_job_reply.h"
+#include "protocol_job_forward.h"
+#include "mach_excServer.h"
-#define LAUNCHD_MIN_JOB_RUN_TIME 10
-#define LAUNCHD_DEFAULT_EXIT_TIMEOUT 20
-#define LAUNCHD_SIGKILL_TIMER 5
+/*
+ * 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
+ * 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_SIGKILL_TIMER 5
+#define LAUNCHD_CLEAN_KILL_TIMER 1
+#define LAUNCHD_JETSAM_PRIORITY_UNSET 0xdead1eebabell
+#define SHUTDOWN_LOG_DIR "/var/log/shutdown"
#define TAKE_SUBSET_NAME "TakeSubsetName"
#define TAKE_SUBSET_PID "TakeSubsetPID"
static bool waiting4removal_new(job_t j, mach_port_t rp);
static void waiting4removal_delete(job_t j, struct waiting_for_removal *w4r);
-struct mspolicy {
- SLIST_ENTRY(mspolicy) sle;
- unsigned int allow:1, per_pid:1;
- const char name[0];
+struct waiting_for_exit {
+ LIST_ENTRY(waiting_for_exit) sle;
+ mach_port_t rp;
+ bool legacy;
};
-static bool mspolicy_new(job_t j, const char *name, bool allow, bool pid_local, bool skip_check);
-static bool mspolicy_copy(job_t j_to, job_t j_from);
-static void mspolicy_setup(launch_data_t obj, const char *key, void *context);
-static bool mspolicy_check(job_t j, const char *name, bool pid_local);
-static void mspolicy_delete(job_t j, struct mspolicy *msp);
+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;
- job_t job;
- uint64_t bad_perf_cnt;
+ 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, special_port_num:10;
+ 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;
+
const char name[0];
};
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 *);
struct socketgroup {
SLIST_ENTRY(socketgroup) sle;
};
};
-static bool socketgroup_new(job_t j, const char *name, int *fds, unsigned int fd_cnt, bool junkfds);
+static bool socketgroup_new(job_t j, const char *name, int *fds, size_t fd_cnt, bool junkfds);
static void socketgroup_delete(job_t j, struct socketgroup *sg);
static void socketgroup_watch(job_t j, struct socketgroup *sg);
static void socketgroup_ignore(job_t j, struct socketgroup *sg);
struct envitem {
SLIST_ENTRY(envitem) sle;
+ bool one_shot;
char *value;
union {
const char key[0];
};
};
-static bool envitem_new(job_t j, const char *k, const char *v, bool global);
+static bool envitem_new(job_t j, const char *k, const char *v, bool global, bool one_shot);
static void envitem_delete(job_t j, struct envitem *ei, bool global);
static void envitem_setup(launch_data_t obj, const char *key, void *context);
+static void envitem_setup_one_shot(launch_data_t obj, const char *key, void *context);
struct limititem {
SLIST_ENTRY(limititem) sle;
struct semaphoreitem {
SLIST_ENTRY(semaphoreitem) sle;
semaphore_reason_t why;
+ bool watching_parent;
int fd;
union {
const char what[0];
#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
+enum {
+ JOBMGR_PHASE_HOPEFULLY_EXITS_FIRST,
+ JOBMGR_PHASE_NORMAL,
+ JOBMGR_PHASE_HOPEFULLY_EXITS_LAST,
+ JOBMGR_PHASE_LAST,
+};
+
+static char *s_phases[JOBMGR_PHASE_LAST + 1] = {
+ "HopefullyExitsFirst",
+ "Normal",
+ "HopefullyExitsLast",
+ "Finalized",
+};
+
struct jobmgr_s {
kq_callback kqjobmgr_callback;
SLIST_ENTRY(jobmgr_s) sle;
SLIST_HEAD(, jobmgr_s) submgrs;
LIST_HEAD(, job_s) jobs;
+ LIST_HEAD(, job_s) jetsam_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 init_audit_session;
jobmgr_t parentmgr;
int reboot_flags;
+ int shutdown_phase;
unsigned int global_on_demand_cnt;
unsigned int hopefully_first_cnt;
unsigned int normal_active_cnt;
- unsigned int sent_stop_to_normal_jobs:1, sent_stop_to_hopefully_last_jobs:1, shutting_down:1, session_initialized:1;
+ 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];
+ uint32_t properties;
union {
const char name[0];
char name_init[0];
};
#define jobmgr_assumes(jm, e) \
- (__builtin_expect(!(e), 0) ? jobmgr_log_bug(jm, __rcs_file_version__, __FILE__, __LINE__, #e), false : true)
+ (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);
+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 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 bool jobmgr_label_test(jobmgr_t jm, const char *str);
static void jobmgr_reap_bulk(jobmgr_t jm, struct kevent *kev);
-static void jobmgr_log_stray_children(jobmgr_t jm);
+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_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_lookup_per_user_context_internal(job_t j, uid_t which_user, bool dispatch, 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 jobmgr_logv(jobmgr_t jm, int pri, int err, const char *msg, va_list ap) __attribute__((format(printf, 4, 0)));
static void jobmgr_log(jobmgr_t jm, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4)));
/* static void jobmgr_log_error(jobmgr_t jm, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4))); */
-static void jobmgr_log_bug(jobmgr_t jm, const char *rcs_rev, const char *path, unsigned int line, const char *test);
-
-#define DO_RUSAGE_SUMMATION 0
+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)
+
+struct suspended_peruser {
+ LIST_ENTRY(suspended_peruser) sle;
+ job_t j;
+};
struct job_s {
- kq_callback kqjob_callback;
+ 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) 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_HEAD(, socketgroup) sockets;
SLIST_HEAD(, calendarinterval) cal_intervals;
SLIST_HEAD(, envitem) global_env;
SLIST_HEAD(, envitem) env;
SLIST_HEAD(, limititem) limits;
- SLIST_HEAD(, mspolicy) mspolicies;
SLIST_HEAD(, machservice) machservices;
SLIST_HEAD(, semaphoreitem) semaphores;
SLIST_HEAD(, waiting_for_removal) removal_watchers;
-#if DO_RUSAGE_SUMMATION
struct rusage ru;
-#endif
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 wait_reply_port; /* we probably should switch to a list of waiters */
uid_t mach_uid;
jobmgr_t mgr;
+ size_t argc;
char **argv;
char *prog;
char *rootdir;
char *workingdir;
char *username;
char *groupname;
+ char *stdinpath;
char *stdoutpath;
char *stderrpath;
char *alt_exc_handler;
+ struct vproc_shmem_s *shmem;
struct machservice *lastlookup;
unsigned int lastlookup_gennum;
#if HAVE_SANDBOX
size_t quarantine_data_sz;
#endif
pid_t p;
- int argc;
int last_exit_status;
- int forkfd;
+ int stdin_fd;
+ int fork_fd;
int log_redirect_fd;
int nice;
- unsigned int timeout;
- unsigned int exit_timeout;
int stdout_err_fd;
- uint64_t sent_sigterm_time;
+ long long jetsam_priority;
+ long long main_thread_priority;
+ uint32_t timeout;
+ uint32_t exit_timeout;
+ uint64_t sent_signal_time;
uint64_t start_time;
uint32_t min_run_time;
uint32_t start_interval;
- unsigned int checkedin:1, anonymous:1, debug:1, inetcompat:1, inetcompat_wait:1,
- ondemand:1, session_create:1, low_pri_io:1, no_init_groups:1, priv_port_has_senders:1,
- importing_global_env:1, importing_hard_limits:1, setmask:1, legacy_mach_job:1, start_pending:1;
+ uint32_t peruser_suspend_count; /* The number of jobs that have disabled this per-user launchd. */
+#if 0
+ /* someday ... */
+ enum {
+ J_TYPE_ANONYMOUS = 1,
+ J_TYPE_LANCHSERVICES,
+ J_TYPE_MACHINIT,
+ 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. */
+ migratory :1; /* The (anonymous) job called vprocmgr_switch_to_session(). */
mode_t mask;
- unsigned int globargv:1, wait4debugger:1, unload_at_exit:1, stall_before_exec:1, only_once:1,
- currently_ignored:1, forced_peers_to_demand_mode:1, setnice:1, hopefully_exits_last:1, removal_pending:1,
- wait4pipe_eof:1, sent_sigkill:1, debug_before_kill:1, weird_bootstrap:1, start_on_mount:1,
- per_user:1, hopefully_exits_first:1, deny_unknown_mslookups:1, unload_at_mig_return:1, abandon_pg:1,
- poll_for_vfs_changes:1, internal_exc_handler:1, deny_job_creation:1;
+ pid_t tracing_pid;
+ mach_port_t audit_session;
+ uuid_t expected_audit_uuid;
const char label[0];
};
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;
#define job_assumes(j, e) \
- (__builtin_expect(!(e), 0) ? job_log_bug(j, __rcs_file_version__, __FILE__, __LINE__, #e), false : true)
+ (unlikely(!(e)) ? job_log_bug(j, __LINE__), false : true)
static void job_import_keys(launch_data_t obj, const char *key, void *context);
static void job_import_bool(job_t j, const char *key, bool value);
static const char *job_active(job_t j);
static void job_watch(job_t j);
static void job_ignore(job_t j);
+static void job_cleanup_after_tracer(job_t j);
static void job_reap(job_t j);
static bool job_useless(job_t j);
static bool job_keepalive(job_t j);
+static void job_dispatch_curious_jobs(job_t j);
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_setup_fd(job_t j, int target_fd, const char *path, int flags);
static void job_postfork_become_user(job_t j);
-#if !TARGET_OS_EMBEDDED
-static void job_enable_audit_for_user(job_t j, uid_t u, char *name);
-#endif
-static void job_find_and_blame_pids_with_weird_uids(job_t j);
-static void job_force_sampletool(job_t j);
+static void job_postfork_test_user(job_t j);
+static void job_log_pids_with_weird_uids(job_t j);
static void job_setup_exception_port(job_t j, task_t target_task);
-static void job_reparent_hack(job_t j, const char *where);
static void job_callback(void *obj, struct kevent *kev);
-static void job_callback_proc(job_t j, int flags, int fflags);
+static void job_callback_proc(job_t j, struct kevent *kev);
static void job_callback_timer(job_t j, void *ident);
static void job_callback_read(job_t j, int ident);
static void job_log_stray_pg(job_t j);
-static job_t job_new_anonymous(jobmgr_t jm, pid_t anonpid);
-static job_t job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv);
-static job_t job_new_via_mach_init(job_t j, const char *cmd, uid_t uid, bool ond);
-static const char *job_prog(job_t j);
-static jobmgr_t job_get_bs(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 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 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_logv(job_t j, int pri, int err, const char *msg, va_list ap) __attribute__((format(printf, 4, 0)));
static void job_log_error(job_t j, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4)));
-static void job_log_bug(job_t j, const char *rcs_rev, const char *path, unsigned int line, const char *test);
+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_exeception_port(job_t j, mach_port_t port);
+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 const struct {
const char *key;
int val;
static bool cronemu_min(struct tm *wtm, int min);
/* miscellaneous file local functions */
-static void ensure_root_bkgd_setup(void);
+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 do_first_per_user_launchd_hack(void);
-static size_t get_kern_max_proc(void);
-static void do_file_init(void) __attribute__((constructor));
+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);
+
+/* For Jetsam. */
+static void jetsam_priority_from_job(job_t j, bool front, jetsam_priority_entry_t *jp);
+static int job_cmp(const job_t *lhs, const job_t *rhs);
+int launchd_set_jetsam_priorities(launch_data_t priorities);
/* file local globals */
-static bool do_apple_internal_magic;
static size_t total_children;
static size_t total_anon_children;
static mach_port_t the_exception_server;
-static bool did_first_per_user_launchd_BootCache_hack;
-#define JOB_BOOTCACHE_HACK_CHECK(j) (j->per_user && !did_first_per_user_launchd_BootCache_hack && (j->mach_uid >= 500) && (j->mach_uid != (uid_t)-2))
-static jobmgr_t background_jobmgr;
static job_t workaround_5477111;
-static mach_timebase_info_data_t tbi;
+static LIST_HEAD(, job_s) s_needing_sessions;
+mach_port_t g_audit_session_port = MACH_PORT_NULL;
+
+#if !TARGET_OS_EMBEDDED
+static job_t s_embedded_privileged_job = (job_t)&root_jobmgr;
+au_asid_t g_audit_session = AU_DEFAUDITSID;
+#else
+static job_t s_embedded_privileged_job = NULL;
+pid_t g_audit_session = 0;
+#endif
+
+static int s_no_hang_fd = -1;
/* process wide globals */
mach_port_t inherited_bootstrap_port;
jobmgr_t root_jobmgr;
-
+bool g_shutdown_debugging = false;
+bool g_verbose_boot = false;
+bool g_embedded_privileged_action = false;
void
job_ignore(job_t j)
void
job_stop(job_t j)
{
- if (!j->p || j->anonymous) {
+ char extralog[100];
+ int32_t newval = 1;
+
+ if (unlikely(!j->p || j->anonymous)) {
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
- job_assumes(j, runtime_kill(j->p, SIGTERM) != -1);
- j->sent_sigterm_time = mach_absolute_time();
-
- if (j->exit_timeout) {
- job_assumes(j, kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER,
- EV_ADD|EV_ONESHOT, NOTE_SECONDS, j->exit_timeout, j) != -1);
+#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) ) {
+ errno = EPERM;
+ return;
+ }
+
+ if( strcmp(j->username, s_embedded_privileged_job->username) != 0 ) {
+ errno = EPERM;
+ return;
+ }
+ } else if( g_embedded_privileged_action ) {
+ errno = EINVAL;
+ return;
}
+#endif
+
+ 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;
+
+ 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->kill_via_shmem) {
+ snprintf(extralog, sizeof(extralog), ": %d remaining transactions", newval + 1);
+ } else {
+ extralog[0] = '\0';
+ }
- job_log(j, LOG_DEBUG, "Sent SIGTERM signal");
+ job_log(j, LOG_DEBUG, "Sent SIGTERM signal%s", extralog);
+ }
+
+ j->stopped = true;
}
launch_data_t
if (j->prog && (tmp = launch_data_new_string(j->prog))) {
launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_PROGRAM);
}
+ if (j->stdinpath && (tmp = launch_data_new_string(j->stdinpath))) {
+ launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_STANDARDINPATH);
+ }
if (j->stdoutpath && (tmp = launch_data_new_string(j->stdoutpath))) {
launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_STANDARDOUTPATH);
}
if (j->stderrpath && (tmp = launch_data_new_string(j->stderrpath))) {
launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_STANDARDERRORPATH);
}
- if (j->argv && (tmp = launch_data_alloc(LAUNCH_DATA_ARRAY))) {
- int i;
+ if (likely(j->argv) && (tmp = launch_data_alloc(LAUNCH_DATA_ARRAY))) {
+ size_t i;
for (i = 0; i < j->argc; i++) {
if ((tmp2 = launch_data_new_string(j->argv[i]))) {
launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_PROGRAMARGUMENTS);
}
+ if (j->kill_via_shmem && (tmp = launch_data_new_bool(true))) {
+ int32_t tmp_cnt = -1;
+
+ launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_ENABLETRANSACTIONS);
+
+ if (j->shmem) {
+ tmp_cnt = j->shmem->vp_shmem_transaction_cnt;
+ }
+
+ if (j->sent_kill_via_shmem) {
+ tmp_cnt++;
+ }
+
+ if ((tmp = launch_data_new_integer(tmp_cnt))) {
+ launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_TRANSACTIONCOUNT);
+ }
+ }
+
if (j->session_create && (tmp = launch_data_new_bool(true))) {
launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_SESSIONCREATE);
}
}
LIST_FOREACH(ji, &jm->jobs, sle) {
- why_active = job_active(ji);
-
- job_log(ji, LOG_DEBUG, "%s", why_active ? why_active : "Inactive");
+ if( (why_active = job_active(ji)) ) {
+ job_log(ji, LOG_DEBUG | LOG_CONSOLE, "%s", why_active);
+ }
}
-
}
static void
-still_alive_with_check(void)
+jobmgr_still_alive_with_check(jobmgr_t jm)
{
- jobmgr_log(root_jobmgr, LOG_NOTICE, "Still alive with %lu/%lu children", total_children, total_anon_children);
-
- jobmgr_log_active_jobs(root_jobmgr);
-
- runtime_closelog(); /* hack to flush logs */
+ 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_active_jobs(jm);
}
jobmgr_t
jobmgr_shutdown(jobmgr_t jm)
{
jobmgr_t jmi, jmn;
- job_t ji;
-
jobmgr_log(jm, LOG_DEBUG, "Beginning job manager shutdown with flags: %s", reboot_flags_to_C_names(jm->reboot_flags));
jm->shutting_down = true;
SLIST_FOREACH_SAFE(jmi, &jm->submgrs, sle, jmn) {
jobmgr_shutdown(jmi);
}
-
- if (jm->hopefully_first_cnt) {
- LIST_FOREACH(ji, &jm->jobs, sle) {
- if (ji->p && ji->hopefully_exits_first) {
- job_stop(ji);
- }
- }
- }
-
- if (debug_shutdown_hangs && jm->parentmgr == NULL && getpid() == 1) {
- runtime_set_timeout(still_alive_with_check, 5);
+
+ 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
}
return jobmgr_do_garbage_collection(jm);
jobmgr_t jmi;
job_t ji;
- jobmgr_log(jm, LOG_DEBUG, "Removed job manager");
-
+ jobmgr_log(jm, LOG_DEBUG, "Removing job manager.");
if (!jobmgr_assumes(jm, SLIST_EMPTY(&jm->submgrs))) {
while ((jmi = SLIST_FIRST(&jm->submgrs))) {
jobmgr_remove(jmi);
}
}
- while ((ji = LIST_FIRST(&jm->jobs))) {
- /* We should only have anonymous jobs left */
- job_assumes(ji, ji->anonymous);
+ 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.");
+ ji->p = 0;
+ }
job_remove(ji);
}
jobmgr_assumes(jm, launchd_mport_close_recv(jm->jm_port) == KERN_SUCCESS);
}
- if (jm == background_jobmgr) {
- background_jobmgr = NULL;
- }
-
if (jm->parentmgr) {
- runtime_del_ref();
+ runtime_del_weak_ref();
SLIST_REMOVE(&jm->parentmgr->submgrs, jm, jobmgr_s, sle);
- } else if (getpid() == 1) {
- jobmgr_log(jm, LOG_DEBUG, "About to call: reboot(%s)", reboot_flags_to_C_names(jm->reboot_flags));
+ } else if (pid1_magic) {
+ eliminate_double_reboot();
+ launchd_log_vm_stats();
+ 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);
- runtime_closelog();
} else {
- runtime_closelog();
jobmgr_log(jm, LOG_DEBUG, "About to exit");
+ runtime_closelog();
exit(EXIT_SUCCESS);
}
struct socketgroup *sg;
struct machservice *ms;
struct limititem *li;
- struct mspolicy *msp;
struct envitem *ei;
-
- if (j->p && j->anonymous) {
- job_reap(j);
- } else if (j->p) {
- job_log(j, LOG_DEBUG, "Removal pended until the job exits");
-
- if (!j->removal_pending) {
- j->removal_pending = true;
- job_stop(j);
+
+#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) ) {
+ errno = EPERM;
+ return;
}
-
+
+ if( strcmp(j->username, s_embedded_privileged_job->username) != 0 ) {
+ errno = EPERM;
+ return;
+ }
+ } else if( g_embedded_privileged_action ) {
+ errno = EINVAL;
return;
}
+#endif
+
+ if (unlikely(j->p)) {
+ if (j->anonymous) {
+ job_reap(j);
+ } else {
+ job_log(j, LOG_DEBUG, "Removal pended until the job exits");
+
+ if (!j->removal_pending) {
+ j->removal_pending = true;
+ job_stop(j);
+ }
+ return;
+ }
+ }
+
+ job_dispatch_curious_jobs(j);
ipc_close_all_with_job(j);
+ job_log(j, LOG_INFO, "Total rusage: utime %ld.%06u stime %ld.%06u maxrss %lu ixrss %lu idrss %lu isrss %lu minflt %lu majflt %lu nswap %lu inblock %lu oublock %lu msgsnd %lu msgrcv %lu nsignals %lu nvcsw %lu nivcsw %lu",
+ j->ru.ru_utime.tv_sec, j->ru.ru_utime.tv_usec,
+ j->ru.ru_stime.tv_sec, j->ru.ru_stime.tv_usec,
+ j->ru.ru_maxrss, j->ru.ru_ixrss, j->ru.ru_idrss, j->ru.ru_isrss,
+ j->ru.ru_minflt, j->ru.ru_majflt,
+ j->ru.ru_nswap, j->ru.ru_inblock, j->ru.ru_oublock,
+ j->ru.ru_msgsnd, j->ru.ru_msgrcv,
+ j->ru.ru_nsignals, j->ru.ru_nvcsw, j->ru.ru_nivcsw);
+
if (j->forced_peers_to_demand_mode) {
job_set_global_on_demand(j, false);
}
- if (!job_assumes(j, j->forkfd == 0)) {
- job_assumes(j, runtime_close(j->forkfd) != -1);
+ if (!job_assumes(j, j->fork_fd == 0)) {
+ job_assumes(j, runtime_close(j->fork_fd) != -1);
+ }
+
+ if (j->stdin_fd) {
+ job_assumes(j, runtime_close(j->stdin_fd) != -1);
}
if (!job_assumes(j, j->log_redirect_fd == 0)) {
job_assumes(j, launchd_mport_deallocate(j->wait_reply_port) == KERN_SUCCESS);
}
- while ((msp = SLIST_FIRST(&j->mspolicies))) {
- mspolicy_delete(j, msp);
- }
while ((sg = SLIST_FIRST(&j->sockets))) {
socketgroup_delete(j, sg);
}
if (j->groupname) {
free(j->groupname);
}
+ if (j->stdinpath) {
+ free(j->stdinpath);
+ }
if (j->stdoutpath) {
free(j->stdoutpath);
}
free(j->j_binpref);
}
if (j->start_interval) {
- runtime_del_ref();
+ runtime_del_weak_ref();
job_assumes(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_DELETE, 0, 0, NULL) != -1);
}
if (j->poll_for_vfs_changes) {
job_assumes(j, kevent_mod((uintptr_t)&j->semaphores, EVFILT_TIMER, EV_DELETE, 0, 0, j) != -1);
}
-
+ 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);
+ }
+ if( j->jetsam_priority != LAUNCHD_JETSAM_PRIORITY_UNSET ) {
+ 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( !uuid_is_null(j->expected_audit_uuid) ) {
+ LIST_REMOVE(j, needing_session_sle);
+ }
+ if( j->embedded_special_privileges ) {
+ s_embedded_privileged_job = NULL;
+ }
+
kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
-
+
LIST_REMOVE(j, sle);
LIST_REMOVE(j, label_hash_sle);
{
launch_data_t tmp_oai;
job_t j = context;
- unsigned int i, fd_cnt = 1;
+ size_t i, fd_cnt = 1;
int *fds;
if (launch_data_get_type(obj) == LAUNCH_DATA_ARRAY) {
}
/* Sigh... at the moment, MIG has maxsize == sizeof(reply union) */
- mxmsgsz = sizeof(union __RequestUnion__job_mig_protocol_vproc_subsystem);
+ mxmsgsz = (typeof(mxmsgsz)) sizeof(union __RequestUnion__job_mig_protocol_vproc_subsystem);
if (job_mig_protocol_vproc_subsystem.maxsize > mxmsgsz) {
mxmsgsz = job_mig_protocol_vproc_subsystem.maxsize;
}
free(argv);
/* jobs can easily be denied creation during shutdown */
- if (!jr) {
+ if (unlikely(jr == NULL)) {
goto out_bad;
}
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, anonpid };
struct kinfo_proc kp;
size_t len = sizeof(kp);
- const char *zombie = NULL;
bool shutdown_state;
job_t jp = NULL, jr = NULL;
+ uid_t kp_euid, kp_uid, kp_svuid;
+ gid_t kp_egid, kp_gid, kp_svgid;
if (!jobmgr_assumes(jm, anonpid != 0)) {
+ errno = EINVAL;
return NULL;
}
if (!jobmgr_assumes(jm, anonpid < 100000)) {
/* The kernel current defines PID_MAX to be 99999, but that define isn't exported */
+ errno = EINVAL;
return NULL;
}
return NULL;
}
- if (len != sizeof(kp)) {
+ if (unlikely(len != sizeof(kp))) {
jobmgr_log(jm, LOG_DEBUG, "Tried to create an anonymous job for nonexistent PID: %u", anonpid);
+ errno = ESRCH;
return NULL;
}
if (!jobmgr_assumes(jm, kp.kp_proc.p_comm[0] != '\0')) {
+ errno = EINVAL;
return NULL;
}
- if (kp.kp_proc.p_stat == SZOMB) {
- jobmgr_log(jm, LOG_DEBUG, "Tried to create an anonymous job for zombie PID: %u", anonpid);
- zombie = "zombie";
+ 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(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);
+ }
+
+ 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;
+
+ 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);
}
switch (kp.kp_eproc.e_ppid) {
/* the kernel */
break;
case 1:
- if (getpid() != 1) {
+ if (!pid1_magic) {
/* we cannot possibly find a parent job_t that is useful in this function */
break;
}
break;
}
+ 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 ((shutdown_state = jm->shutting_down)) {
+ if (unlikely(shutdown_state = jm->shutting_down)) {
jm->shutting_down = false;
}
- if (jobmgr_assumes(jm, (jr = job_new(jm, AUTO_PICK_LEGACY_LABEL, zombie ? zombie : kp.kp_proc.p_comm, NULL)) != NULL)) {
- u_int proc_fflags = NOTE_EXEC|NOTE_EXIT /* |NOTE_REAP */;
+ if (jobmgr_assumes(jm, (jr = job_new(jm, AUTO_PICK_ANONYMOUS_LABEL, kp.kp_proc.p_comm, NULL)) != NULL)) {
+ u_int proc_fflags = NOTE_EXEC|NOTE_FORK|NOTE_EXIT|NOTE_REAP;
total_anon_children++;
jr->anonymous = true;
/* anonymous process reaping is messy */
LIST_INSERT_HEAD(&jm->active_jobs[ACTIVE_JOB_HASH(jr->p)], jr, pid_hash_sle);
- if (kevent_mod(jr->p, EVFILT_PROC, EV_ADD, proc_fflags, 0, root_jobmgr) == -1 && job_assumes(jr, errno == ESRCH)) {
+ if (unlikely(kevent_mod(jr->p, EVFILT_PROC, EV_ADD, proc_fflags, 0, root_jobmgr) == -1) && job_assumes(jr, errno == ESRCH)) {
/* zombies are weird */
job_log(jr, LOG_ERR, "Failed to add kevent for PID %u. Will unload at MIG return", jr->p);
jr->unload_at_mig_return = true;
}
- if (jp) {
- job_assumes(jr, mspolicy_copy(jr, jp));
- }
-
- if (shutdown_state && jm->hopefully_first_cnt == 0) {
- job_log(jr, LOG_APPLEONLY, "This process showed up to the party while all the guests were leaving. Odds are that it will have a miserable time");
+ if (unlikely(shutdown_state && jm->hopefully_first_cnt == 0)) {
+ 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 : "");
}
- if (shutdown_state) {
+ if (unlikely(shutdown_state)) {
jm->shutting_down = true;
}
job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv)
{
const char *const *argv_tmp = argv;
+ char tmp_path[PATH_MAX];
char auto_label[1000];
const char *bn = NULL;
char *co;
size_t minlabel_len;
- int i, cc = 0;
+ size_t i, cc = 0;
job_t j;
launchd_assert(offsetof(struct job_s, kqjob_callback) == 0);
- if (jm->shutting_down) {
+ if (unlikely(jm->shutting_down)) {
errno = EINVAL;
return NULL;
}
- if (prog == NULL && argv == NULL) {
+ if (unlikely(prog == NULL && argv == NULL)) {
errno = EINVAL;
return NULL;
}
- if (label == AUTO_PICK_LEGACY_LABEL) {
- bn = prog ? prog : basename((char *)argv[0]); /* prog for auto labels is kp.kp_kproc.p_comm */
- snprintf(auto_label, sizeof(auto_label), "%s.%s", sizeof(void *) == 8 ? "0xdeadbeeffeedface" : "0xbabecafe", bn);
+ 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;
+ } else {
+ strlcpy(tmp_path, argv[0], sizeof(tmp_path));
+ bn = basename(tmp_path); /* prog for auto labels is kp.kp_kproc.p_comm */
+ }
+ snprintf(auto_label, sizeof(auto_label), "%s.%s.%s", sizeof(void *) == 8 ? "0xdeadbeeffeedface" : "0xbabecafe", anon_or_legacy, bn);
label = auto_label;
/* This is so we can do gross things later. See NOTE_EXEC for anonymous jobs */
minlabel_len = strlen(label) + MAXCOMLEN;
return NULL;
}
- if (label == auto_label) {
- snprintf((char *)j->label, strlen(label) + 1, "%p.%s", j, bn);
+ 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);
}
j->currently_ignored = true;
j->ondemand = true;
j->checkedin = true;
-
+ j->jetsam_priority = LAUNCHD_JETSAM_PRIORITY_UNSET;
+ uuid_clear(j->expected_audit_uuid);
+
if (prog) {
j->prog = strdup(prog);
if (!job_assumes(j, j->prog != NULL)) {
}
}
- if (argv) {
- while (*argv_tmp++)
+ if (likely(argv)) {
+ while (*argv_tmp++) {
j->argc++;
+ }
for (i = 0; i < j->argc; i++) {
cc += strlen(argv[i]) + 1;
j->argv[i] = NULL;
}
+ if( strcmp(j->label, "com.apple.WindowServer") == 0 ) {
+ j->has_console = true;
+ }
+
LIST_INSERT_HEAD(&jm->jobs, j, sle);
LIST_INSERT_HEAD(&label_hash[hash_label(j->label)], j, label_hash_sle);
+ uuid_clear(j->expected_audit_uuid);
job_log(j, LOG_DEBUG, "Conceived");
{
job_t j = jobmgr_import2(root_jobmgr, pload);
- if (j == NULL) {
+ if (unlikely(j == NULL)) {
return NULL;
}
+ /* Since jobs are effectively stalled until they get security sessions assigned
+ * to them, we may wish to reconsider this behavior of calling the job "enabled"
+ * as far as other jobs with the OtherJobEnabled KeepAlive criterion set.
+ */
+ job_dispatch_curious_jobs(j);
return job_dispatch(j, false);
}
job_t *ja;
size_t i, c = launch_data_array_get_count(pload);
- ja = alloca(c * sizeof(job_t ));
+ ja = alloca(c * sizeof(job_t));
for (i = 0; i < c; i++) {
- if ((ja[i] = jobmgr_import2(root_jobmgr, launch_data_array_get_index(pload, i)))) {
+ 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);
}
for (i = 0; i < c; i++) {
- if (ja[i] == NULL) {
- continue;
+ if (likely(ja[i])) {
+ job_dispatch_curious_jobs(ja[i]);
+ job_dispatch(ja[i], false);
}
- job_dispatch(ja[i], false);
}
return resp;
}
j->no_init_groups = !value;
found_key = true;
+ } else if( strcasecmp(key, LAUNCH_JOBKEY_IGNOREPROCESSGROUPATSHUTDOWN) == 0 ) {
+ j->ignore_pg_at_shutdown = value;
+ found_key = true;
}
break;
case 'r':
if (strcasecmp(key, LAUNCH_JOBKEY_ENABLEGLOBBING) == 0) {
j->globargv = value;
found_key = true;
+ } else if (strcasecmp(key, LAUNCH_JOBKEY_ENABLETRANSACTIONS) == 0) {
+ j->kill_via_shmem = 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 ) {
+ 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;
}
break;
case 'w':
break;
}
- if (!found_key) {
+ if (unlikely(!found_key)) {
job_log(j, LOG_WARNING, "Unknown key for boolean: %s", key);
}
}
} else if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADFROMHOSTS) == 0) {
return;
} else if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE) == 0) {
- job_reparent_hack(j, value);
return;
}
break;
where2put = &j->stdoutpath;
} else if (strcasecmp(key, LAUNCH_JOBKEY_STANDARDERRORPATH) == 0) {
where2put = &j->stderrpath;
+ } else if (strcasecmp(key, LAUNCH_JOBKEY_STANDARDINPATH) == 0) {
+ where2put = &j->stdinpath;
+ 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);
+ /* 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);
+ } else {
+ j->stdin_fd = 0;
+ }
#if HAVE_SANDBOX
} else if (strcasecmp(key, LAUNCH_JOBKEY_SANDBOXPROFILE) == 0) {
where2put = &j->seatbelt_profile;
break;
}
- if (where2put) {
+ if (likely(where2put)) {
job_assumes(j, (*where2put = strdup(value)) != NULL);
} else {
- job_log(j, LOG_WARNING, "Unknown key: %s", key);
+ /* See rdar://problem/5496612. These two are okay. */
+ if( strncmp(key, "SHAuthorizationRight", sizeof("SHAuthorizationRight")) != 0 && strncmp(key, "ServiceDescription", sizeof("ServiceDescription")) != 0 ) {
+ job_log(j, LOG_WARNING, "Unknown key: %s", key);
+ }
}
}
case 'e':
case 'E':
if (strcasecmp(key, LAUNCH_JOBKEY_EXITTIMEOUT) == 0) {
- if (value < 0) {
+ if (unlikely(value < 0)) {
job_log(j, LOG_WARNING, "%s less than zero. Ignoring.", LAUNCH_JOBKEY_EXITTIMEOUT);
- } else if (value > UINT32_MAX) {
+ } else if (unlikely(value > UINT32_MAX)) {
job_log(j, LOG_WARNING, "%s is too large. Ignoring.", LAUNCH_JOBKEY_EXITTIMEOUT);
} else {
- j->exit_timeout = value;
+ j->exit_timeout = (typeof(j->exit_timeout)) value;
}
+ } else if( strcasecmp(key, LAUNCH_JOBKEY_EMBEDDEDMAINTHREADPRIORITY) == 0 ) {
+ j->main_thread_priority = value;
+ }
+ break;
+ case 'j':
+ case 'J':
+ if( strcasecmp(key, LAUNCH_JOBKEY_JETSAMPRIORITY) == 0 ) {
+ job_log(j, LOG_DEBUG, "Importing job with priority: %lld", value);
+ j->jetsam_priority = (typeof(j->jetsam_priority))value;
+ LIST_INSERT_HEAD(&j->mgr->jetsam_jobs, j, jetsam_sle);
+ j->mgr->jetsam_jobs_cnt++;
}
break;
case 'n':
case 'N':
if (strcasecmp(key, LAUNCH_JOBKEY_NICE) == 0) {
- j->nice = value;
- j->setnice = true;
+ if (unlikely(value < PRIO_MIN)) {
+ job_log(j, LOG_WARNING, "%s less than %d. Ignoring.", LAUNCH_JOBKEY_NICE, PRIO_MIN);
+ } else if (unlikely(value > PRIO_MAX)) {
+ job_log(j, LOG_WARNING, "%s is greater than %d. Ignoring.", LAUNCH_JOBKEY_NICE, PRIO_MAX);
+ } else {
+ j->nice = (typeof(j->nice)) value;
+ j->setnice = true;
+ }
}
break;
case 't':
case 'T':
if (strcasecmp(key, LAUNCH_JOBKEY_TIMEOUT) == 0) {
- if (value < 0) {
+ if (unlikely(value < 0)) {
job_log(j, LOG_WARNING, "%s less than zero. Ignoring.", LAUNCH_JOBKEY_TIMEOUT);
- } else if (value > UINT32_MAX) {
+ } else if (unlikely(value > UINT32_MAX)) {
job_log(j, LOG_WARNING, "%s is too large. Ignoring.", LAUNCH_JOBKEY_TIMEOUT);
} else {
- j->timeout = value;
+ j->timeout = (typeof(j->timeout)) value;
}
} else if (strcasecmp(key, LAUNCH_JOBKEY_THROTTLEINTERVAL) == 0) {
if (value < 0) {
} else if (value > UINT32_MAX) {
job_log(j, LOG_WARNING, "%s is too large. Ignoring.", LAUNCH_JOBKEY_THROTTLEINTERVAL);
} else {
- j->min_run_time = value;
+ j->min_run_time = (typeof(j->min_run_time)) value;
}
}
break;
case 's':
case 'S':
if (strcasecmp(key, LAUNCH_JOBKEY_STARTINTERVAL) == 0) {
- if (value <= 0) {
+ if (unlikely(value <= 0)) {
job_log(j, LOG_WARNING, "%s is not greater than zero. Ignoring.", LAUNCH_JOBKEY_STARTINTERVAL);
- } else if (value > UINT32_MAX) {
+ } else if (unlikely(value > UINT32_MAX)) {
job_log(j, LOG_WARNING, "%s is too large. Ignoring.", LAUNCH_JOBKEY_STARTINTERVAL);
} else {
- runtime_add_ref();
- 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, value, j) != -1);
+ 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) {
}
}
#endif
+ case 's':
+ case 'S':
+ if( strcasecmp(key, LAUNCH_JOBKEY_SECURITYSESSIONUUID) == 0 ) {
+ size_t tmpsz = launch_data_get_opaque_size(value);
+ if( job_assumes(j, tmpsz == sizeof(uuid_t)) ) {
+ memcpy(j->expected_audit_uuid, launch_data_get_opaque(value), sizeof(uuid_t));
+ }
+ }
break;
default:
break;
case 'E':
if (strcasecmp(key, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES) == 0) {
launch_data_dict_iterate(value, envitem_setup, j);
- }
+ }
break;
case 'u':
case 'U':
case 'M':
if (strcasecmp(key, LAUNCH_JOBKEY_MACHSERVICES) == 0) {
launch_data_dict_iterate(value, machservice_setup, j);
- } else if (strcasecmp(key, LAUNCH_JOBKEY_MACHSERVICELOOKUPPOLICIES) == 0) {
- launch_data_dict_iterate(value, mspolicy_setup, j);
}
break;
default:
if (job_assumes(j, j->j_binpref = malloc(value_cnt * sizeof(*j->j_binpref)))) {
j->j_binpref_cnt = value_cnt;
for (i = 0; i < value_cnt; i++) {
- j->j_binpref[i] = launch_data_get_integer(launch_data_array_get_index(value, i));
+ j->j_binpref[i] = (cpu_type_t) launch_data_get_integer(launch_data_array_get_index(value, i));
}
}
}
job_t j = context;
launch_data_type_t kind;
- if (obj == NULL) {
+ if (!launchd_assumes(obj != NULL)) {
return;
}
const char **argv = NULL;
job_t j;
- if (pload == NULL) {
+ if (!jobmgr_assumes(jm, pload != NULL)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (unlikely(launch_data_get_type(pload) != LAUNCH_DATA_DICTIONARY)) {
errno = EINVAL;
return NULL;
}
- if (launch_data_get_type(pload) != LAUNCH_DATA_DICTIONARY) {
+ if (unlikely(!(tmp = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_LABEL)))) {
errno = EINVAL;
return NULL;
}
- if (!(tmp = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_LABEL))) {
+ if (unlikely(launch_data_get_type(tmp) != LAUNCH_DATA_STRING)) {
errno = EINVAL;
return NULL;
}
- if (launch_data_get_type(tmp) != LAUNCH_DATA_STRING) {
+ if (unlikely(!(label = launch_data_get_string(tmp)))) {
errno = EINVAL;
return NULL;
}
- if (!(label = launch_data_get_string(tmp))) {
+#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))) ) {
+ errno = EPERM;
+ return NULL;
+ }
+
+ const char *username = NULL;
+ if( likely(tmp && launch_data_get_type(tmp) == LAUNCH_DATA_STRING) ) {
+ username = launch_data_get_string(tmp);
+ } else {
+ errno = EPERM;
+ return NULL;
+ }
+
+ if( !jobmgr_assumes(jm, s_embedded_privileged_job->username != NULL && username != NULL) ) {
+ errno = EPERM;
+ return NULL;
+ }
+
+ if( unlikely(strcmp(s_embedded_privileged_job->username, username) != 0) ) {
+ errno = EPERM;
+ return NULL;
+ }
+ } else if( g_embedded_privileged_action ) {
errno = EINVAL;
return NULL;
}
+#endif
if ((tmp = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_PROGRAM)) &&
(launch_data_get_type(tmp) == LAUNCH_DATA_STRING)) {
argv[i] = NULL;
}
- if ((j = job_find(label)) != NULL) {
+ /* Hack to make sure the proper job manager is set the whole way through. */
+ 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;
+ }
+
+ jobmgr_log(jm, LOG_DEBUG, "Importing %s.", label);
+
+ if (unlikely((j = job_find(label)) != NULL)) {
errno = EEXIST;
return NULL;
- } else if (!jobmgr_label_test(jm, label)) {
+ } else if (unlikely(!jobmgr_label_test(jm, label))) {
errno = EINVAL;
return NULL;
}
- if ((j = job_new(jm, label, prog, argv))) {
+ 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) ) {
+ 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);
+ LIST_INSERT_HEAD(&s_needing_sessions, j, needing_session_sle);
+ errno = ENEEDAUTH;
+ } else {
+ job_log(j, LOG_DEBUG, "No security session specified.");
+ j->audit_session = MACH_PORT_NULL;
+ }
}
return j;
jobmgr_log(jm, LOG_ERR, "Empty job labels are not allowed");
return false;
}
-
+
for (ptr = str; *ptr; ptr++) {
if (iscntrl(*ptr)) {
jobmgr_log(jm, LOG_ERR, "ASCII control characters are not allowed in job labels. Index: %td Value: 0x%hhx", ptr - str, *ptr);
return false;
}
}
-
+
strtoll(str, &endstr, 0);
if (str != endstr) {
jobmgr_log(jm, LOG_ERR, "Job labels are not allowed to begin with numbers: %s", str);
return false;
}
-
+
if ((strncasecmp(str, "com.apple.launchd", strlen("com.apple.launchd")) == 0) ||
(strncasecmp(str, "com.apple.launchctl", strlen("com.apple.launchctl")) == 0)) {
jobmgr_log(jm, LOG_ERR, "Job labels are not allowed to use a reserved prefix: %s", str);
job_t ji;
LIST_FOREACH(ji, &label_hash[hash_label(label)], label_hash_sle) {
- if (ji->removal_pending) {
- continue; /* 5351245 */
- } else if (ji->mgr->shutting_down) {
- continue; /* 5488633 */
+ if (unlikely(ji->removal_pending || ji->mgr->shutting_down)) {
+ continue; /* 5351245 and 5488633 respectively */
}
if (strcmp(ji->label, label) == 0) {
return NULL;
}
+/* Should try and consolidate with job_mig_intran2() and jobmgr_find_by_pid(). */
job_t
-jobmgr_find_by_pid(jobmgr_t jm, pid_t p, bool create_anon)
+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 ) {
+ if (ji->p == p && (!ji->anonymous || (ji->anonymous && anon_okay)) ) {
+ return ji;
+ }
+ }
- LIST_FOREACH(ji, &jm->active_jobs[ACTIVE_JOB_HASH(p)], pid_hash_sle) {
- if (ji->p == p) {
+ jobmgr_t jmi = NULL;
+ SLIST_FOREACH( jmi, &jm->submgrs, sle ) {
+ if( (ji = jobmgr_find_by_pid_deep(jmi, p, anon_okay)) ) {
break;
}
}
- if (ji) {
- return ji;
- } else if (create_anon) {
- return job_new_anonymous(jm, p);
- } else {
- return NULL;
+ return ji;
+}
+
+job_t
+jobmgr_find_by_pid(jobmgr_t jm, pid_t p, bool create_anon)
+{
+ job_t ji;
+
+ LIST_FOREACH(ji, &jm->active_jobs[ACTIVE_JOB_HASH(p)], pid_hash_sle) {
+ if (ji->p == p) {
+ return ji;
+ }
}
+
+ return create_anon ? job_new_anonymous(jm, p) : NULL;
}
job_t
job_t ji;
if (jm->jm_port == mport) {
- jobmgr_assumes(jm, (ji = jobmgr_find_by_pid(jm, upid, true)) != NULL);
- return ji;
+ return jobmgr_find_by_pid(jm, upid, true);
}
SLIST_FOREACH(jmi, &jm->submgrs, sle) {
job_t
job_mig_intran(mach_port_t p)
{
- struct ldcred ldc;
+ struct ldcred *ldc = runtime_get_caller_creds();
job_t jr;
- runtime_get_caller_creds(&ldc);
-
- jr = job_mig_intran2(root_jobmgr, p, ldc.pid);
+ 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;
+ 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);
+ 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);
}
}
* 'j' can be invalid at this point. We should fix this up after Leopard ships.
*/
- if (j && j != workaround_5477111 && j->unload_at_mig_return) {
+ if (unlikely(j && (j != workaround_5477111) && j->unload_at_mig_return)) {
job_log(j, LOG_NOTICE, "Unloading PID %u at MIG return.", j->p);
job_remove(j);
}
size_t i, kp_cnt, len = sizeof(struct kinfo_proc) * get_kern_max_proc();
struct kinfo_proc *kp;
-#if TARGET_OS_EMBEDDED
- if (!do_apple_internal_magic) {
+ if (!do_apple_internal_logging) {
return;
}
-#endif
+
+ runtime_ktrace(RTKT_LAUNCHD_FINDING_STRAY_PG, j->p, 0, 0);
if (!job_assumes(j, (kp = malloc(len)) != NULL)) {
return;
struct rusage ru;
int status;
+ bool is_system_bootstrapper = j->is_bootstrapper && pid1_magic && !j->mgr->parentmgr;
+
job_log(j, LOG_DEBUG, "Reaping");
- if (j->weird_bootstrap) {
- mach_msg_size_t mxmsgsz = sizeof(union __RequestUnion__job_mig_protocol_vproc_subsystem);
-
- if (job_mig_protocol_vproc_subsystem.maxsize > mxmsgsz) {
- mxmsgsz = job_mig_protocol_vproc_subsystem.maxsize;
- }
+ if (j->shmem) {
+ job_assumes(j, vm_deallocate(mach_task_self(), (vm_address_t)j->shmem, getpagesize()) == 0);
+ j->shmem = NULL;
+ }
- job_assumes(j, runtime_add_mport(j->mgr->jm_port, protocol_vproc_server, mxmsgsz) == KERN_SUCCESS);
- j->weird_bootstrap = false;
+ if (unlikely(j->weird_bootstrap)) {
+ int64_t junk = 0;
+ job_mig_swap_integer(j, VPROC_GSK_WEIRD_BOOTSTRAP, 0, 0, &junk);
}
- if (j->log_redirect_fd && !j->wait4pipe_eof) {
- job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
- j->log_redirect_fd = 0;
+ if (j->log_redirect_fd && !j->legacy_LS_job) {
+ job_log_stdouterr(j); /* one last chance */
+
+ if (j->log_redirect_fd) {
+ job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
+ j->log_redirect_fd = 0;
+ }
}
- if (j->forkfd) {
- job_assumes(j, runtime_close(j->forkfd) != -1);
- j->forkfd = 0;
+ if (j->fork_fd) {
+ job_assumes(j, runtime_close(j->fork_fd) != -1);
+ j->fork_fd = 0;
}
if (j->anonymous) {
*/
job_log_stray_pg(j);
if (!j->abandon_pg) {
- job_assumes(j, runtime_killpg(j->p, SIGTERM) != -1 || errno == ESRCH);
+ if (unlikely(runtime_killpg(j->p, SIGTERM) == -1 && errno != ESRCH)) {
+#ifdef __LP64__
+ job_log(j, LOG_APPLEONLY, "Bug: 5487498");
+#else
+ job_assumes(j, false);
+#endif
+ }
}
-
+
/*
* 5020256
*
if (j->exit_timeout) {
kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
}
-
- if (j->anonymous) {
- total_anon_children--;
- } else {
- runtime_del_ref();
- total_children--;
- }
+
LIST_REMOVE(j, pid_hash_sle);
if (j->wait_reply_port) {
j->wait_reply_port = MACH_PORT_NULL;
}
- if (j->sent_sigterm_time) {
- uint64_t td_sec, td_usec, td = (mach_absolute_time() - j->sent_sigterm_time) * tbi.numer / tbi.denom;
+ 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);
td_sec = td / NSEC_PER_SEC;
td_usec = (td % NSEC_PER_SEC) / NSEC_PER_USEC;
- job_log(j, LOG_INFO, "Exited %lld.%06lld seconds after %s was sent",
- td_sec, td_usec, signal_to_C_name(j->sent_sigkill ? SIGKILL : SIGTERM));
+ job_log(j, LOG_DEBUG, "Exited %llu.%06llu seconds after the first signal was sent", td_sec, td_usec);
}
-#if DO_RUSAGE_SUMMATION
timeradd(&ru.ru_utime, &j->ru.ru_utime, &j->ru.ru_utime);
timeradd(&ru.ru_stime, &j->ru.ru_stime, &j->ru.ru_stime);
j->ru.ru_maxrss += ru.ru_maxrss;
j->ru.ru_nsignals += ru.ru_nsignals;
j->ru.ru_nvcsw += ru.ru_nvcsw;
j->ru.ru_nivcsw += ru.ru_nivcsw;
-#endif
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
job_log(j, LOG_WARNING, "Exited with exit code: %d", WEXITSTATUS(status));
if (WIFSIGNALED(status)) {
int s = WTERMSIG(status);
- if (SIGKILL == s || SIGTERM == s) {
+ if ((SIGKILL == s || SIGTERM == s) && !j->stopped) {
job_log(j, LOG_NOTICE, "Exited: %s", strsignal(s));
- } else {
- job_log(j, LOG_WARNING, "Exited abnormally: %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;
+ }
+
+ if( is_system_bootstrapper && j->crashed ) {
+ job_log(j, LOG_ERR | LOG_CONSOLE, "The %s bootstrapper has crashed: %s", j->mgr->name, strsignal(s));
+ }
}
}
+ 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) ) {
+ machservice_drain_port(msi);
+ }
+
+ if( !j->did_exec && msi->reset && job_assumes(j, !msi->isActive) ) {
+ machservice_resetport(j, msi);
+ }
+ }
+ }
+
+ struct suspended_peruser *spi = NULL;
+ 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--;
+ if( spi->j->peruser_suspend_count == 0 ) {
+ job_dispatch(spi->j, false);
+ }
+ LIST_REMOVE(spi, sle);
+ free(spi);
+ }
+
+ struct waiting_for_exit *w4e = NULL;
+ while( (w4e = LIST_FIRST(&j->exit_watchers)) ) {
+ waiting4exit_delete(j, w4e);
+ }
+
+ if (j->anonymous) {
+ total_anon_children--;
+ if( j->migratory ) {
+ runtime_del_ref();
+ }
+ } else {
+ runtime_del_ref();
+ total_children--;
+ }
+
+ if( j->has_console ) {
+ g_wsp = 0;
+ }
+
if (j->hopefully_exits_first) {
j->mgr->hopefully_first_cnt--;
} else if (!j->anonymous && !j->hopefully_exits_last) {
j->mgr->normal_active_cnt--;
}
j->last_exit_status = status;
+ 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;
}
}
+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;
+ SLIST_FOREACH_SAFE( ji, &s_curious_jobs, curious_jobs_sle, jt ) {
+ struct semaphoreitem *si = NULL;
+ SLIST_FOREACH( si, &ji->semaphores, sle ) {
+ if( !(si->why == OTHER_JOB_ENABLED || si->why == OTHER_JOB_DISABLED) ) {
+ continue;
+ }
+
+ if( strncmp(si->what, j->label, strlen(j->label)) == 0 ) {
+ job_log(ji, LOG_DEBUG, "Dispatching out of interest in \"%s\".", j->label);
+
+ job_dispatch(ji, false);
+ /* ji could be removed here, so don't do anything with it or its semaphores
+ * after this point.
+ */
+ break;
+ }
+ }
+ }
+}
+
job_t
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) ) {
+ return NULL;
+ }
+
+#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) ) {
+ errno = EPERM;
+ return NULL;
+ }
+
+ if( strcmp(j->username, s_embedded_privileged_job->username) != 0 ) {
+ errno = EPERM;
+ return NULL;
+ }
+ } else if( g_embedded_privileged_action ) {
+ errno = EINVAL;
+ return NULL;
+ }
+#endif
+
/*
* The whole job removal logic needs to be consolidated. The fact that
* a job can be removed from just about anywhere makes it easy to have
* used after the deallocation. In particular, during job iteration.
*
* This is a classic example. The act of dispatching a job may delete it.
- */
+ */
if (!job_active(j)) {
if (job_useless(j)) {
job_remove(j);
return NULL;
- } else if (kickstart || job_keepalive(j)) {
+ }
+ if( unlikely(j->per_user && j->peruser_suspend_count > 0) ) {
+ return NULL;
+ }
+
+ if (kickstart || job_keepalive(j)) {
+ job_log(j, LOG_DEBUG, "Starting job (kickstart = %s)", kickstart ? "true" : "false");
job_start(j);
} else {
+ job_log(j, LOG_DEBUG, "Watching job (kickstart = %s)", kickstart ? "true" : "false");
job_watch(j);
/*
}
}
} else {
- job_log(j, LOG_DEBUG, "Tried to dispatch an already active job.");
+ job_log(j, LOG_DEBUG, "Tried to dispatch an already active job (%s).", job_active(j));
}
return j;
rsz = read(j->log_redirect_fd, buf, BIG_PIPE_SIZE);
- if (rsz == 0) {
+ if (unlikely(rsz == 0)) {
job_log(j, LOG_DEBUG, "Standard out/error pipe closed");
close_log_redir = true;
- } else if (!job_assumes(j, rsz != -1)) {
- close_log_redir = true;
+ } else if (rsz == -1) {
+ if( !job_assumes(j, errno == EAGAIN) ) {
+ close_log_redir = true;
+ }
} else {
buf[rsz] = '\0';
free(buf);
- if (close_log_redir) {
+ if (unlikely(close_log_redir)) {
job_assumes(j, runtime_close(j->log_redirect_fd) != -1);
j->log_redirect_fd = 0;
job_dispatch(j, false);
void
job_kill(job_t j)
{
- if (!j->p || j->anonymous) {
+ if (unlikely(!j->p || j->anonymous)) {
return;
}
j->sent_sigkill = true;
- job_assumes(j, kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER,
- EV_ADD, NOTE_SECONDS, LAUNCHD_SIGKILL_TIMER, j) != -1);
+ 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);
- job_log(j, LOG_DEBUG, "Sent SIGKILL signal.");
+ job_log(j, LOG_DEBUG, "Sent SIGKILL signal");
}
void
-job_callback_proc(job_t j, int flags __attribute__((unused)), int fflags)
+job_log_children_without_exec(job_t j)
{
- if ((fflags & NOTE_EXEC) && j->anonymous) {
- int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, j->p };
- struct kinfo_proc kp;
- size_t len = sizeof(kp);
+ /* <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 (!do_apple_internal_logging || j->anonymous || j->per_user) {
+ return;
+ }
+
+ if (!job_assumes(j, (kp = malloc(len)) != NULL)) {
+ return;
+ }
+ if (!job_assumes(j, sysctl(mib, (u_int) mib_sz, kp, &len, NULL, 0) != -1)) {
+ goto out;
+ }
+
+ kp_cnt = len / sizeof(struct kinfo_proc);
+
+ for (i = 0; i < kp_cnt; i++) {
+#ifndef KERN_PROC_PPID
+ if (kp[i].kp_eproc.e_ppid != j->p) {
+ continue;
+ }
+#endif
+ if (kp[i].kp_proc.p_flag & P_EXEC) {
+ 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);
+ }
+
+out:
+ free(kp);
+}
+
+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;
+ 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);
+
+ /* 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).
+ */
+ 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_callback_proc(job_t j, struct kevent *kev)
+{
+ bool program_changed = false;
+ int fflags = kev->fflags;
+
+ job_log(j, LOG_DEBUG, "EVFILT_PROC event for job:");
+ 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()) ) {
+ /* 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
+ * indication that the parent exited between sysctl(3) and kevent_mod(). The
+ * reparenting of the PID should be atomic to us, so in that case, we reap the
+ * job as normal.
+ *
+ * Otherwise, we wait for the death of the parent tracer and then reap, just as we
+ * would if a job died while we were sampling it at shutdown.
+ */
+ 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;
+ j->reap_after_trace = true;
+ return;
+ }
+ }
+ }
+ } else if( !j->anonymous ) {
+ if( j->tracing_pid == (pid_t)kev->ident ) {
+ job_cleanup_after_tracer(j);
+
+ return;
+ } 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;
+ return;
+ }
+ }
+ }
+
+ if (fflags & NOTE_EXEC) {
+ 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);
- if (job_assumes(j, sysctl(mib, 4, &kp, &len, NULL, 0) != -1)) {
- char newlabel[1000];
+ /* 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)) {
+ char newlabel[1000];
- snprintf(newlabel, sizeof(newlabel), "%p.%s", j, kp.kp_proc.p_comm);
+ snprintf(newlabel, sizeof(newlabel), "%p.anonymous.%s", j, kp.kp_proc.p_comm);
- job_log(j, LOG_DEBUG, "Program changed. Updating the label to: %s", newlabel);
+ job_log(j, LOG_INFO, "Program changed. Updating the label to: %s", newlabel);
+ j->lastlookup = NULL;
+ j->lastlookup_gennum = 0;
- LIST_REMOVE(j, label_hash_sle);
- strcpy((char *)j->label, newlabel);
- LIST_INSERT_HEAD(&label_hash[hash_label(j->label)], j, label_hash_sle);
+ LIST_REMOVE(j, label_hash_sle);
+ strcpy((char *)j->label, newlabel);
+ LIST_INSERT_HEAD(&label_hash[hash_label(j->label)], j, label_hash_sle);
+ }
+ } else {
+ j->did_exec = true;
+ job_log(j, LOG_DEBUG, "Program changed");
}
}
if (fflags & NOTE_FORK) {
- job_log(j, LOG_DEBUG, "Called 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()." : "");
+ job_log_children_without_exec(j);
}
if (fflags & NOTE_EXIT) {
job_reap(j);
- if (j->anonymous) {
+ if( !j->anonymous ) {
+ j = job_dispatch(j, false);
+ } else {
job_remove(j);
j = NULL;
- } else {
- j = job_dispatch(j, false);
}
}
- /* NOTE_REAP sanity checking is disabled for now while we try and diagnose 5289559 */
-#if 0
if (j && (fflags & NOTE_REAP)) {
- job_assumes(j, flags & EV_ONESHOT);
- job_assumes(j, flags & EV_EOF);
-
job_assumes(j, j->p == 0);
}
-#endif
}
void
job_callback_timer(job_t j, void *ident)
{
if (j == ident) {
+ job_log(j, LOG_DEBUG, "j == ident (%p)", ident);
job_dispatch(j, true);
} else if (&j->semaphores == ident) {
+ job_log(j, LOG_DEBUG, "&j->semaphores == ident (%p)", ident);
job_dispatch(j, false);
} else if (&j->start_interval == ident) {
+ job_log(j, LOG_DEBUG, "&j->start_interval == ident (%p)", 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);
+ 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 = (mach_absolute_time() - j->sent_sigterm_time) * tbi.numer / tbi.denom;
+ uint64_t td = runtime_get_nanoseconds_since(j->sent_signal_time);
td /= NSEC_PER_SEC;
- td -= j->exit_timeout;
-
- job_log(j, LOG_ERR, "Did not die after sending SIGKILL %llu seconds ago...", td);
+ 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);
+ }
+
+ STAILQ_INSERT_TAIL(&j->mgr->pending_samples, j, pending_samples_sle);
+ j->pending_sample = true;
+ jobmgr_dequeue_next_sample(j->mgr);
} else {
- job_force_sampletool(j);
- if (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);
+ 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);
}
- job_log(j, LOG_WARNING, "Exit timeout elapsed (%u seconds). Killing.", j->exit_timeout);
- job_kill(j);
}
} else {
job_assumes(j, false);
{
if (ident == j->log_redirect_fd) {
job_log_stdouterr(j);
+ } else if (ident == j->stdin_fd) {
+ job_dispatch(j, true);
} else {
socketgroup_callback(j);
}
jobmgr_reap_bulk(jmi, kev);
}
- if ((j = jobmgr_find_by_pid(jm, kev->ident, false))) {
+ if ((j = jobmgr_find_by_pid(jm, (pid_t)kev->ident, false))) {
kev->udata = j;
job_callback(j, kev);
}
jobmgr_callback(void *obj, struct kevent *kev)
{
jobmgr_t jm = obj;
+ job_t ji;
switch (kev->filter) {
case EVFILT_PROC:
jobmgr_reap_bulk(jm, kev);
- if (launchd_assumes(root_jobmgr != NULL)) {
- root_jobmgr = jobmgr_do_garbage_collection(root_jobmgr);
- }
+ root_jobmgr = jobmgr_do_garbage_collection(root_jobmgr);
break;
case EVFILT_SIGNAL:
switch (kev->ident) {
- case SIGTERM:
+ case SIGTERM:
return launchd_shutdown();
case SIGUSR1:
return calendarinterval_callback();
+ case SIGUSR2:
+ fake_shutdown_in_progress = true;
+ runtime_setlogmask(LOG_UPTO(LOG_DEBUG));
+
+ runtime_closelog(); /* HACK -- force 'start' time to be set */
+
+ if (pid1_magic) {
+ int64_t now = runtime_get_wall_time();
+
+ jobmgr_log(jm, LOG_NOTICE, "Anticipatory shutdown began at: %lld.%06llu", now / USEC_PER_SEC, now % USEC_PER_SEC);
+
+ LIST_FOREACH(ji, &root_jobmgr->jobs, sle) {
+ if (ji->per_user && ji->p) {
+ job_assumes(ji, runtime_kill(ji->p, SIGUSR2) != -1);
+ }
+ }
+ } else {
+ jobmgr_log(jm, LOG_NOTICE, "Anticipatory per-user launchd shutdown");
+ }
+
+ return;
default:
return (void)jobmgr_assumes(jm, false);
}
jobmgr_dispatch_all_semaphores(jm);
break;
case EVFILT_TIMER:
- if (jobmgr_assumes(jm, kev->ident == (uintptr_t)&sorted_calendar_events)) {
+ if( kev->ident == (uintptr_t)&sorted_calendar_events ) {
calendarinterval_callback();
+ } else if( kev->ident == (uintptr_t)jm ) {
+ jobmgr_log(jm, LOG_DEBUG, "Shutdown timer firing.");
+ jobmgr_still_alive_with_check(jm);
+ } else if( kev->ident == (uintptr_t)&jm->reboot_flags ) {
+ jobmgr_do_garbage_collection(jm);
+ }
+ break;
+ case EVFILT_VNODE:
+ if( kev->ident == (uintptr_t)s_no_hang_fd ) {
+ int _no_hang_fd = open("/dev/autofs_nowait", O_EVTONLY | O_NONBLOCK);
+ if( unlikely(_no_hang_fd != -1) ) {
+ 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);
+ s_no_hang_fd = _fd(_no_hang_fd);
+ }
+ } else if( pid1_magic && g_console && kev->ident == (uintptr_t)fileno(g_console) ) {
+ int cfd = -1;
+ if( launchd_assumes((cfd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) != -1) ) {
+ _fd(cfd);
+ if( !launchd_assumes((g_console = fdopen(cfd, "w")) != NULL) ) {
+ close(cfd);
+ }
+ }
}
break;
default:
switch (kev->filter) {
case EVFILT_PROC:
- return job_callback_proc(j, kev->flags, kev->fflags);
+ return job_callback_proc(j, kev);
case EVFILT_TIMER:
- return job_callback_timer(j, (void *)kev->ident);
+ return job_callback_timer(j, (void *) kev->ident);
case EVFILT_VNODE:
return semaphoreitem_callback(j, kev);
case EVFILT_READ:
- return job_callback_read(j, kev->ident);
+ return job_callback_read(j, (int) kev->ident);
case EVFILT_MACHPORT:
return (void)job_dispatch(j, true);
default:
void
job_start(job_t j)
{
- uint64_t td, tnow = mach_absolute_time();
+ uint64_t td;
int spair[2];
int execspair[2];
int oepair[2];
char nbuf[64];
pid_t c;
bool sipc = false;
- u_int proc_fflags = /* NOTE_EXEC|NOTE_FORK| */ NOTE_EXIT /* |NOTE_REAP */;
-
+ u_int proc_fflags = NOTE_EXIT|NOTE_FORK|NOTE_EXEC|NOTE_REAP;
+
if (!job_assumes(j, j->mgr != NULL)) {
return;
}
-
- if (job_active(j)) {
+
+ if (unlikely(job_active(j))) {
job_log(j, LOG_DEBUG, "Already started");
return;
}
-
- job_assumes(j, tnow > j->start_time);
-
+
/*
* Some users adjust the wall-clock and then expect software to not notice.
- * Therefore, launchd must use an absolute clock instead of gettimeofday()
- * or time() wherever possible.
+ * Therefore, launchd must use an absolute clock instead of the wall clock
+ * wherever possible.
*/
- td = (tnow - j->start_time) * tbi.numer / tbi.denom;
+ td = runtime_get_nanoseconds_since(j->start_time);
td /= NSEC_PER_SEC;
-
+
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.
*/
-
+
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);
job_ignore(j);
return;
}
-
- j->sent_sigterm_time = 0;
-
- if (!j->legacy_mach_job) {
- sipc = (!SLIST_EMPTY(&j->sockets) || !SLIST_EMPTY(&j->machservices));
-#if TARGET_OS_EMBEDDED
- if (j->username && strcmp(j->username, "mobile") == 0 && strncmp(j->label, "com.apple.", strlen("com.apple.")) != 0) {
- sipc = false;
- }
-#endif
+
+ if (likely(!j->legacy_mach_job)) {
+ sipc = ((!SLIST_EMPTY(&j->sockets) || !SLIST_EMPTY(&j->machservices)) && !j->deny_job_creation) || j->embedded_special_privileges;
}
- j->checkedin = false;
-
- if (sipc) {
+ if( sipc ) {
job_assumes(j, socketpair(AF_UNIX, SOCK_STREAM, 0, spair) != -1);
}
-
+
job_assumes(j, socketpair(AF_UNIX, SOCK_STREAM, 0, execspair) != -1);
-
- if (!j->legacy_mach_job && job_assumes(j, pipe(oepair) != -1)) {
+
+ 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);
}
-
- j->start_time = tnow;
-
+
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);
+ job_ignore(j);
+
job_assumes(j, runtime_close(execspair[0]) == 0);
job_assumes(j, runtime_close(execspair[1]) == 0);
if (sipc) {
job_assumes(j, runtime_close(spair[0]) == 0);
job_assumes(j, runtime_close(spair[1]) == 0);
}
- if (!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);
j->log_redirect_fd = 0;
}
- job_assumes(j, kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, 1, j) != -1);
- job_ignore(j);
break;
case 0:
- if (_vproc_post_fork_ping()) {
+ if (unlikely(_vproc_post_fork_ping())) {
_exit(EXIT_FAILURE);
}
if (!j->legacy_mach_job) {
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) {
job_assumes(j, runtime_close(spair[0]) == 0);
snprintf(nbuf, sizeof(nbuf), "%d", spair[1]);
job_start_child(j);
break;
default:
+ j->start_time = runtime_get_opaque_time();
+
job_log(j, LOG_DEBUG, "Started as PID: %u", c);
-
+
+ j->did_exec = false;
+ j->checkedin = false;
j->start_pending = false;
-
+ j->reaped = false;
+ j->crashed = false;
+ j->stopped = false;
+ if( j->needs_kickoff ) {
+ j->needs_kickoff = false;
+
+ if( SLIST_EMPTY(&j->semaphores) ) {
+ j->ondemand = false;
+ }
+ }
+
+ if( j->has_console ) {
+ g_wsp = c;
+ }
+
runtime_add_ref();
total_children++;
LIST_INSERT_HEAD(&j->mgr->active_jobs[ACTIVE_JOB_HASH(c)], j, pid_hash_sle);
-
- if (JOB_BOOTCACHE_HACK_CHECK(j)) {
- did_first_per_user_launchd_BootCache_hack = true;
- }
-
- if (!j->legacy_mach_job) {
+
+ if (likely(!j->legacy_mach_job)) {
job_assumes(j, runtime_close(oepair[1]) != -1);
}
j->p = c;
- if (j->hopefully_exits_first) {
+ if (unlikely(j->hopefully_exits_first)) {
j->mgr->hopefully_first_cnt++;
- } else if (!j->hopefully_exits_last) {
+ } else if (likely(!j->hopefully_exits_last)) {
j->mgr->normal_active_cnt++;
}
- j->forkfd = _fd(execspair[0]);
+ j->fork_fd = _fd(execspair[0]);
job_assumes(j, runtime_close(execspair[1]) == 0);
if (sipc) {
job_assumes(j, runtime_close(spair[1]) == 0);
} else {
job_reap(j);
}
+
+ j->wait4debugger_oneshot = false;
- if (!j->stall_before_exec) {
+ struct envitem *ei = NULL, *et = NULL;
+ SLIST_FOREACH_SAFE( ei, &j->env, sle, et ) {
+ if( ei->one_shot ) {
+ SLIST_REMOVE(&j->env, ei, envitem, sle);
+ }
+ }
+
+ if (likely(!j->stall_before_exec)) {
job_uncork_fork(j);
}
break;
}
}
-void
-do_first_per_user_launchd_hack(void)
-{
- char *bcct_tool[] = { "/usr/sbin/BootCacheControl", "tag", NULL };
- int dummystatus;
- pid_t bcp;
-
- if (launchd_assumes((bcp = vfork()) != -1)) {
- if (bcp == 0) {
- execve(bcct_tool[0], bcct_tool, environ);
- _exit(EXIT_FAILURE);
- } else {
- launchd_assumes(waitpid(bcp, &dummystatus, 0) != -1);
- }
- }
-}
-
void
job_start_child(job_t j)
{
+ typeof(posix_spawn) *psf;
const char *file2exec = "/usr/libexec/launchproxy";
const char **argv;
posix_spawnattr_t spattr;
int gflags = GLOB_NOSORT|GLOB_NOCHECK|GLOB_TILDE|GLOB_DOOFFS;
- pid_t junk_pid;
glob_t g;
short spflags = POSIX_SPAWN_SETEXEC;
size_t binpref_out_cnt = 0;
- int i;
-
- if (JOB_BOOTCACHE_HACK_CHECK(j)) {
- do_first_per_user_launchd_hack();
- }
+ size_t i;
job_assumes(j, posix_spawnattr_init(&spattr) == 0);
job_setup_attributes(j);
- if (j->argv && j->globargv) {
+ if (unlikely(j->argv && j->globargv)) {
g.gl_offs = 1;
for (i = 0; i < j->argc; i++) {
if (i > 0) {
}
g.gl_pathv[0] = (char *)file2exec;
argv = (const char **)g.gl_pathv;
- } else if (j->argv) {
+ } else if (likely(j->argv)) {
argv = alloca((j->argc + 2) * sizeof(char *));
argv[0] = file2exec;
for (i = 0; i < j->argc; i++) {
argv[2] = NULL;
}
- if (!j->inetcompat) {
+ if (likely(!j->inetcompat)) {
argv++;
}
- if (j->wait4debugger) {
+ if (unlikely(j->wait4debugger || j->wait4debugger_oneshot)) {
job_log(j, LOG_WARNING, "Spawned and waiting for the debugger to attach before continuing...");
spflags |= POSIX_SPAWN_START_SUSPENDED;
}
job_assumes(j, posix_spawnattr_setflags(&spattr, spflags) == 0);
- if (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);
}
}
#endif
- if (j->prog) {
- errno = posix_spawn(&junk_pid, j->inetcompat ? file2exec : j->prog, NULL, &spattr, (char *const*)argv, environ);
- job_log_error(j, LOG_ERR, "posix_spawn(\"%s\", ...)", j->prog);
- } else {
- errno = posix_spawnp(&junk_pid, j->inetcompat ? file2exec : argv[0], NULL, &spattr, (char *const*)argv, environ);
- job_log_error(j, LOG_ERR, "posix_spawnp(\"%s\", ...)", argv[0]);
+ psf = j->prog ? posix_spawn : posix_spawnp;
+
+ if (likely(!j->inetcompat)) {
+ 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);
+
#if HAVE_SANDBOX
out_bad:
#endif
jobmgr_setup_env_from_other_jobs(jm->parentmgr);
}
- LIST_FOREACH(ji, &jm->jobs, sle) {
+ LIST_FOREACH(ji, &jm->global_env_jobs, global_env_sle) {
SLIST_FOREACH(ei, &ji->global_env, sle) {
setenv(ei->key, ei->value, 1);
}
}
void
-job_find_and_blame_pids_with_weird_uids(job_t j)
+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;
uid_t u = j->mach_uid;
-#if TARGET_OS_EMBEDDED
- if (!do_apple_internal_magic) {
+ if (!do_apple_internal_logging) {
return;
}
-#endif
+
kp = malloc(len);
if (!job_assumes(j, kp != NULL)) {
return;
}
+
+ runtime_ktrace(RTKT_LAUNCHD_FINDING_WEIRD_UIDS, j->p, u, 0);
+
if (!job_assumes(j, sysctl(mib, 3, kp, &len, NULL, 0) != -1)) {
goto out;
}
free(kp);
}
-#if !TARGET_OS_EMBEDDED
void
-job_enable_audit_for_user(job_t j, uid_t u, char *name)
+job_postfork_test_user(job_t j)
{
- auditinfo_t auinfo = {
- .ai_auid = u,
- .ai_asid = j->p,
- };
- long au_cond;
+ /* This function is all about 5201578 */
- if (!job_assumes(j, auditon(A_GETCOND, &au_cond, sizeof(long)) == 0)) {
- _exit(EXIT_FAILURE);
+ const char *home_env_var = getenv("HOME");
+ const char *user_env_var = getenv("USER");
+ const char *logname_env_var = getenv("LOGNAME");
+ uid_t tmp_uid, local_uid = getuid();
+ gid_t tmp_gid, local_gid = getgid();
+ char shellpath[PATH_MAX];
+ char homedir[PATH_MAX];
+ char loginname[2000];
+ struct passwd *pwe;
+
+
+ if (!job_assumes(j, home_env_var && user_env_var && logname_env_var
+ && strcmp(user_env_var, logname_env_var) == 0)) {
+ goto out_bad;
}
- if (au_cond != AUC_NOAUDIT) {
- if (!job_assumes(j, au_user_mask(name, &auinfo.ai_mask) == 0)) {
- _exit(EXIT_FAILURE);
- } else if (!job_assumes(j, setaudit(&auinfo) == 0)) {
- _exit(EXIT_FAILURE);
- }
+ if ((pwe = getpwnam(user_env_var)) == NULL) {
+ job_log(j, LOG_ERR, "The account \"%s\" has been deleted out from under us!", user_env_var);
+ goto out_bad;
}
-}
+
+ /*
+ * We must copy the results of getpw*().
+ *
+ * Why? Because subsequent API calls may call getpw*() as a part of
+ * their implementation. Since getpw*() returns a [now thread scoped]
+ * global, we must therefore cache the results before continuing.
+ */
+
+ tmp_uid = pwe->pw_uid;
+ tmp_gid = pwe->pw_gid;
+
+ strlcpy(shellpath, pwe->pw_shell, sizeof(shellpath));
+ strlcpy(loginname, pwe->pw_name, sizeof(loginname));
+ strlcpy(homedir, pwe->pw_dir, sizeof(homedir));
+
+ if (strcmp(loginname, logname_env_var) != 0) {
+ job_log(j, LOG_ERR, "The %s environmental variable changed out from under us!", "USER");
+ goto out_bad;
+ }
+ if (strcmp(homedir, home_env_var) != 0) {
+ job_log(j, LOG_ERR, "The %s environmental variable changed out from under us!", "HOME");
+ goto out_bad;
+ }
+ if (local_uid != tmp_uid) {
+ job_log(j, LOG_ERR, "The %cID of the account (%u) changed out from under us (%u)!",
+ 'U', tmp_uid, local_uid);
+ goto out_bad;
+ }
+ if (local_gid != tmp_gid) {
+ job_log(j, LOG_ERR, "The %cID of the account (%u) changed out from under us (%u)!",
+ 'G', tmp_gid, local_gid);
+ goto out_bad;
+ }
+
+ return;
+out_bad:
+#if 0
+ 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.");
#endif
+}
void
job_postfork_become_user(job_t j)
uid_t desired_uid = -1;
if (getuid() != 0) {
- return;
+ return job_postfork_test_user(j);
}
/*
} else if (j->mach_uid) {
if ((pwe = getpwuid(j->mach_uid)) == NULL) {
job_log(j, LOG_ERR, "getpwuid(\"%u\") failed", j->mach_uid);
- job_find_and_blame_pids_with_weird_uids(j);
+ job_log_pids_with_weird_uids(j);
_exit(EXIT_FAILURE);
}
} else {
strlcpy(loginname, pwe->pw_name, sizeof(loginname));
strlcpy(homedir, pwe->pw_dir, sizeof(homedir));
- if (pwe->pw_expire && time(NULL) >= pwe->pw_expire) {
+ if (unlikely(pwe->pw_expire && time(NULL) >= pwe->pw_expire)) {
job_log(j, LOG_ERR, "Expired account");
_exit(EXIT_FAILURE);
}
- if (j->username && strcmp(j->username, loginname) != 0) {
+ if (unlikely(j->username && strcmp(j->username, loginname) != 0)) {
job_log(j, LOG_WARNING, "Suspicious setup: User \"%s\" maps to user: %s", j->username, loginname);
- } else if (j->mach_uid && (j->mach_uid != desired_uid)) {
+ } else if (unlikely(j->mach_uid && (j->mach_uid != desired_uid))) {
job_log(j, LOG_WARNING, "Suspicious setup: UID %u maps to UID %u", j->mach_uid, desired_uid);
}
if (j->groupname) {
struct group *gre;
- if ((gre = getgrnam(j->groupname)) == NULL) {
+ if (unlikely((gre = getgrnam(j->groupname)) == NULL)) {
job_log(j, LOG_ERR, "getgrnam(\"%s\") failed", j->groupname);
_exit(EXIT_FAILURE);
}
desired_gid = gre->gr_gid;
}
-#if !TARGET_OS_EMBEDDED
- job_enable_audit_for_user(j, desired_uid, loginname);
-#endif
-
if (!job_assumes(j, setlogin(loginname) != -1)) {
_exit(EXIT_FAILURE);
}
* called after setgid(). See 4616864 for more information.
*/
- if (!j->no_init_groups) {
+ if (likely(!j->no_init_groups)) {
+ #if 1
if (!job_assumes(j, initgroups(loginname, desired_gid) != -1)) {
_exit(EXIT_FAILURE);
}
+ #else
+ /* Do our own little initgroups(). We do this to guarantee that we're
+ * always opted into dynamic group resolution in the kernel. initgroups(3)
+ * does not make this guarantee.
+ */
+ 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);
+
+ if( !job_assumes(j, syscall(SYS_initgroups, ngroups, groups, desired_uid) != -1) ) {
+ _exit(EXIT_FAILURE);
+ }
+ #endif
}
if (!job_assumes(j, setuid(desired_uid) != -1)) {
r = confstr(_CS_DARWIN_USER_TEMP_DIR, tmpdirpath, sizeof(tmpdirpath));
- if (r > 0 && r < sizeof(tmpdirpath)) {
+ if (likely(r > 0 && r < sizeof(tmpdirpath))) {
setenv("TMPDIR", tmpdirpath, 0);
}
struct limititem *li;
struct envitem *ei;
- if (j->setnice) {
+ if (unlikely(j->setnice)) {
job_assumes(j, setpriority(PRIO_PROCESS, 0, j->nice) != -1);
}
}
}
- if (!j->inetcompat && j->session_create) {
+#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 (j->low_pri_io) {
+ if (unlikely(j->low_pri_io)) {
job_assumes(j, setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE) != -1);
}
- if (j->rootdir) {
+ if (unlikely(j->rootdir)) {
job_assumes(j, chroot(j->rootdir) != -1);
job_assumes(j, chdir(".") != -1);
}
job_postfork_become_user(j);
- if (j->workingdir) {
+ if (unlikely(j->workingdir)) {
job_assumes(j, chdir(j->workingdir) != -1);
}
- if (j->setmask) {
+ if (unlikely(j->setmask)) {
umask(j->mask);
}
- job_setup_fd(j, STDOUT_FILENO, j->stdoutpath, O_WRONLY|O_APPEND|O_CREAT);
- job_setup_fd(j, STDERR_FILENO, j->stderrpath, O_WRONLY|O_APPEND|O_CREAT);
+ if (j->stdin_fd) {
+ job_assumes(j, dup2(j->stdin_fd, STDIN_FILENO) != -1);
+ } else {
+ job_setup_fd(j, STDIN_FILENO, j->stdinpath, O_RDONLY|O_CREAT);
+ }
+ job_setup_fd(j, STDOUT_FILENO, j->stdoutpath, O_WRONLY|O_CREAT|O_APPEND);
+ job_setup_fd(j, STDERR_FILENO, j->stderrpath, O_WRONLY|O_CREAT|O_APPEND);
jobmgr_setup_env_from_other_jobs(j->mgr);
setenv(ei->key, ei->value, 1);
}
+ if( do_apple_internal_logging ) {
+ setenv(LAUNCHD_DO_APPLE_INTERNAL_LOGGING, "true", 1);
+ }
+
+#if !TARGET_OS_EMBEDDED
+ if( j->jetsam_priority != LAUNCHD_JETSAM_PRIORITY_UNSET ) {
+ job_assumes(j, proc_setpcontrol(PROC_SETPC_TERMINATE) == 0);
+ }
+#endif
+
+#if TARGET_OS_EMBEDDED
+ if( j->main_thread_priority != 0 ) {
+ struct sched_param params;
+ bzero(¶ms, sizeof(params));
+ params.sched_priority = j->main_thread_priority;
+ job_assumes(j, pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶ms) != -1);
+ }
+#endif
+
/*
* We'd like to call setsid() unconditionally, but we have reason to
* believe that prevents launchd from being able to send signals to
struct dirent *de;
bool r = 0;
- if (!dd) {
+ if (unlikely(!dd)) {
return -1;
}
head_later = LIST_FIRST(&sorted_calendar_events)->when_next;
- /* Workaround 5225889 */
- kevent_mod((uintptr_t)&sorted_calendar_events, EVFILT_TIMER, EV_DELETE, 0, 0, root_jobmgr);
-
if (job_assumes(j, kevent_mod((uintptr_t)&sorted_calendar_events, EVFILT_TIMER, EV_ADD, NOTE_ABSOLUTE|NOTE_SECONDS, head_later, root_jobmgr) != -1)) {
char time_string[100];
size_t time_string_len;
ctime_r(&later, time_string);
time_string_len = strlen(time_string);
- if (time_string_len && time_string[time_string_len - 1] == '\n') {
+ if (likely(time_string_len && time_string[time_string_len - 1] == '\n')) {
time_string[time_string_len - 1] = '\0';
}
}
void
-jobmgr_log_bug(jobmgr_t jm, const char *rcs_rev, const char *path, unsigned int line, const char *test)
+jobmgr_log_bug(jobmgr_t jm, unsigned int line)
{
+ static const char *file;
int saved_errno = errno;
- const char *file = strrchr(path, '/');
char buf[100];
- extract_rcsid_substr(rcs_rev, buf, sizeof(buf));
+ runtime_ktrace1(RTKT_LAUNCHD_BUG);
+
+ extract_rcsid_substr(__rcs_file_version__, buf, sizeof(buf));
if (!file) {
- file = path;
- } else {
- file += 1;
+ file = strrchr(__FILE__, '/');
+ if (!file) {
+ file = __FILE__;
+ } else {
+ file += 1;
+ }
}
- jobmgr_log(jm, LOG_NOTICE, "Bug: %s:%u (%s):%u: %s", file, line, buf, saved_errno, test);
+ /* the only time 'jm' should not be set is if setting up the first bootstrap fails for some reason */
+ if (likely(jm)) {
+ jobmgr_log(jm, LOG_NOTICE, "Bug: %s:%u (%s):%u", file, line, buf, saved_errno);
+ } else {
+ runtime_syslog(LOG_NOTICE, "Bug: %s:%u (%s):%u", file, line, buf, saved_errno);
+ }
}
void
-job_log_bug(job_t j, const char *rcs_rev, const char *path, unsigned int line, const char *test)
+job_log_bug(job_t j, unsigned int line)
{
+ static const char *file;
int saved_errno = errno;
- const char *file = strrchr(path, '/');
char buf[100];
- extract_rcsid_substr(rcs_rev, buf, sizeof(buf));
+ runtime_ktrace1(RTKT_LAUNCHD_BUG);
+
+ extract_rcsid_substr(__rcs_file_version__, buf, sizeof(buf));
if (!file) {
- file = path;
- } else {
- file += 1;
+ file = strrchr(__FILE__, '/');
+ if (!file) {
+ file = __FILE__;
+ } else {
+ file += 1;
+ }
}
- job_log(j, LOG_NOTICE, "Bug: %s:%u (%s):%u: %s", file, line, buf, saved_errno, test);
+ /* 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 {
+ runtime_syslog(LOG_NOTICE, "Bug: %s:%u (%s):%u", file, line, buf, saved_errno);
+ }
}
void
job_logv(job_t j, int pri, int err, const char *msg, va_list ap)
{
- struct runtime_syslog_attr attr = { "com.apple.launchd", j->label, j->mgr->name, pri, getuid(), getpid(), j->p };
+ const char *label2use = j ? j->label : "com.apple.launchd.NULL";
+ const char *mgr2use = j ? j->mgr->name : "NULL";
+ struct runtime_syslog_attr attr = { g_my_label, label2use, mgr2use, pri, getuid(), getpid(), j ? j->p : 0 };
char *newmsg;
int oldmask = 0;
size_t newmsgsz;
newmsg = alloca(newmsgsz);
if (err) {
+ #if !TARGET_OS_EMBEDDED
snprintf(newmsg, newmsgsz, "%s: %s", msg, strerror(err));
+ #else
+ snprintf(newmsg, newmsgsz, "(%s) %s: %s", label2use, msg, strerror(err));
+ #endif
} else {
+ #if !TARGET_OS_EMBEDDED
snprintf(newmsg, newmsgsz, "%s", msg);
+ #else
+ snprintf(newmsg, newmsgsz, "(%s) %s", label2use, msg);
+ #endif
}
- if (j->debug) {
+ if( j && unlikely(j->debug) ) {
oldmask = setlogmask(LOG_UPTO(LOG_DEBUG));
}
runtime_vsyslog(&attr, newmsg, ap);
- if (j->debug) {
+ if( j && unlikely(j->debug) ) {
setlogmask(oldmask);
}
}
if (jm->parentmgr) {
jobmgr_logv(jm->parentmgr, pri, 0, newmsg, ap);
} else {
- struct runtime_syslog_attr attr = { "com.apple.launchd", "com.apple.launchd", jm->name, pri, getuid(), getpid(), getpid() };
+ struct runtime_syslog_attr attr = { g_my_label, g_my_label, jm->name, pri, getuid(), getpid(), getpid() };
runtime_vsyslog(&attr, newmsg, ap);
}
semaphoreitem_watch(job_t j, struct semaphoreitem *si)
{
char *parentdir, tmp_path[PATH_MAX];
- const char *which_path = si->what;
int saved_errno = 0;
- int fflags = 0;
+ int fflags = NOTE_DELETE|NOTE_RENAME;
switch (si->why) {
- case PATH_EXISTS:
- fflags = NOTE_DELETE|NOTE_RENAME|NOTE_REVOKE|NOTE_EXTEND|NOTE_WRITE;
- break;
- case PATH_MISSING:
- fflags = NOTE_DELETE|NOTE_RENAME;
- break;
case DIR_NOT_EMPTY:
case PATH_CHANGES:
- fflags = NOTE_DELETE|NOTE_RENAME|NOTE_REVOKE|NOTE_EXTEND|NOTE_WRITE|NOTE_ATTRIB|NOTE_LINK;
+ fflags |= NOTE_ATTRIB|NOTE_LINK;
+ /* fall through */
+ case PATH_EXISTS:
+ fflags |= NOTE_REVOKE|NOTE_EXTEND|NOTE_WRITE;
+ /* fall through */
+ case PATH_MISSING:
break;
default:
return;
/* See 5321044 for why we do the do-while loop and 5415523 for why ENOENT is checked */
do {
if (si->fd == -1) {
- if ((si->fd = _fd(open(which_path, O_EVTONLY|O_NOCTTY))) == -1) {
- which_path = parentdir;
- si->fd = _fd(open(which_path, O_EVTONLY|O_NOCTTY));
+ struct stat sb;
+ 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
+ * open(2)s the file (like a character device that waits for a carrier signal) or
+ * (b) preventing other processes from obtaining an exclusive lock on the file, even
+ * though we're opening it with O_EVTONLY.
+ *
+ * The main point of contention is that O_EVTONLY doesn't actually mean "event only".
+ * It means "Don't prevent unmounts of this descriptor's volume". We work around this
+ * 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) ) {
+ si->fd = _fd(open(si->what, O_EVTONLY | O_NOCTTY | O_NONBLOCK));
+ }
+ }
+
+ 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;
}
}
if (si->fd == -1) {
- return job_log_error(j, LOG_ERR, "Path monitoring failed on \"%s\"", which_path);
+ return job_log_error(j, LOG_ERR, "Path monitoring failed on \"%s\"", si->what);
}
- job_log(j, LOG_DEBUG, "Watching Vnode: %d", si->fd);
+ job_log(j, LOG_DEBUG, "Watching %svnode (%s): %d", si->watching_parent ? "parent ": "", si->what, si->fd);
if (kevent_mod(si->fd, EVFILT_VNODE, EV_ADD, fflags, 0, j) == -1) {
saved_errno = errno;
job_assumes(j, runtime_close(si->fd) == 0);
si->fd = -1;
}
- } while ((si->fd == -1) && (saved_errno == ENOENT));
+ } while (unlikely((si->fd == -1) && (saved_errno == ENOENT)));
if (saved_errno == ENOTSUP) {
/*
case PATH_EXISTS:
case PATH_MISSING:
case DIR_NOT_EMPTY:
+ job_log(j, LOG_DEBUG, "P%s changed (%u): %s", si->watching_parent ? "arent path" : "ath", si->why, si->what);
break;
default:
continue;
si->fd = -1; /* this will get fixed in semaphoreitem_watch() */
}
- job_log(j, LOG_DEBUG, "Watch path modified: %s", si->what);
-
- if (si->why == PATH_CHANGES) {
- j->start_pending = true;
+ 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( !invalidation_reason[0] ) {
+ job_assumes(j, runtime_close(si->fd) == 0);
+ si->fd = -1; /* this will get fixed in semaphoreitem_watch() */
+ semaphoreitem_watch(j, si);
+ }
+ /* Need to think about what should happen if the parent directory goes invalid. */
}
-
+
job_dispatch(j, false);
}
+struct cal_dict_walk {
+ job_t j;
+ struct tm tmptm;
+};
+
void
calendarinterval_new_from_obj_dict_walk(launch_data_t obj, const char *key, void *context)
{
- struct tm *tmptm = context;
+ struct cal_dict_walk *cdw = context;
+ struct tm *tmptm = &cdw->tmptm;
+ job_t j = cdw->j;
int64_t val;
- if (LAUNCH_DATA_INTEGER != launch_data_get_type(obj)) {
+ if (unlikely(LAUNCH_DATA_INTEGER != launch_data_get_type(obj))) {
/* hack to let caller know something went wrong */
tmptm->tm_sec = -1;
return;
val = launch_data_get_integer(obj);
- if (strcasecmp(key, LAUNCH_JOBKEY_CAL_MINUTE) == 0) {
- tmptm->tm_min = val;
+ 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 ) {
+ 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) {
- tmptm->tm_hour = val;
+ 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) {
- tmptm->tm_mday = val;
+ 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) {
- tmptm->tm_wday = val;
+ 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) {
- tmptm->tm_mon = val;
- tmptm->tm_mon -= 1; /* 4798263 cron compatibility */
+ 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 {
+ tmptm->tm_mon = (typeof(tmptm->tm_mon)) val;
+ tmptm->tm_mon -= 1; /* 4798263 cron compatibility */
+ }
}
}
bool
calendarinterval_new_from_obj(job_t j, launch_data_t obj)
{
- struct tm tmptm;
+ struct cal_dict_walk cdw;
- memset(&tmptm, 0, sizeof(0));
+ cdw.j = j;
+ memset(&cdw.tmptm, 0, sizeof(0));
- tmptm.tm_min = -1;
- tmptm.tm_hour = -1;
- tmptm.tm_mday = -1;
- tmptm.tm_wday = -1;
- tmptm.tm_mon = -1;
+ cdw.tmptm.tm_min = -1;
+ cdw.tmptm.tm_hour = -1;
+ cdw.tmptm.tm_mday = -1;
+ cdw.tmptm.tm_wday = -1;
+ cdw.tmptm.tm_mon = -1;
if (!job_assumes(j, obj != NULL)) {
return false;
}
- if (LAUNCH_DATA_DICTIONARY != launch_data_get_type(obj)) {
+ if (unlikely(LAUNCH_DATA_DICTIONARY != launch_data_get_type(obj))) {
return false;
}
- launch_data_dict_iterate(obj, calendarinterval_new_from_obj_dict_walk, &tmptm);
+ launch_data_dict_iterate(obj, calendarinterval_new_from_obj_dict_walk, &cdw);
- if (tmptm.tm_sec == -1) {
+ if (unlikely(cdw.tmptm.tm_sec == -1)) {
return false;
}
- return calendarinterval_new(j, &tmptm);
+ return calendarinterval_new(j, &cdw.tmptm);
}
bool
calendarinterval_setalarm(j, ci);
- runtime_add_ref();
+ runtime_add_weak_ref();
return true;
}
free(ci);
- runtime_del_ref();
+ runtime_del_weak_ref();
}
void
struct calendarinterval *ci = LIST_FIRST(&sorted_calendar_events);
time_t now = time(NULL);
- if (ci && (ci->when_next < now)) {
+ if (unlikely(ci && (ci->when_next < now))) {
jobmgr_assumes(root_jobmgr, raise(SIGUSR1) != -1);
}
}
}
bool
-socketgroup_new(job_t j, const char *name, int *fds, unsigned int fd_cnt, bool junkfds)
+socketgroup_new(job_t j, const char *name, int *fds, size_t fd_cnt, bool junkfds)
{
struct socketgroup *sg = calloc(1, sizeof(struct socketgroup) + strlen(name) + 1);
SLIST_INSERT_HEAD(&j->sockets, sg, sle);
- runtime_add_ref();
+ runtime_add_weak_ref();
return true;
}
free(sg->fds);
free(sg);
- runtime_del_ref();
+ runtime_del_weak_ref();
}
void
char buf[10000];
unsigned int i, buf_off = 0;
- if (sg->junkfds) {
+ if (unlikely(sg->junkfds)) {
return;
}
for (i = 0; i < sg->fd_cnt; i++) {
job_assumes(j, kev[i].flags & EV_ERROR);
- errno = kev[i].data;
+ errno = (typeof(errno)) kev[i].data;
job_assumes(j, kev[i].data == 0);
}
}
}
bool
-envitem_new(job_t j, const char *k, const char *v, bool global)
+envitem_new(job_t j, const char *k, const char *v, bool global, bool one_shot)
{
struct envitem *ei = calloc(1, sizeof(struct envitem) + strlen(k) + 1 + strlen(v) + 1);
strcpy(ei->key_init, k);
ei->value = ei->key_init + strlen(k) + 1;
strcpy(ei->value, v);
+ ei->one_shot = one_shot;
if (global) {
+ if (SLIST_EMPTY(&j->global_env)) {
+ LIST_INSERT_HEAD(&j->mgr->global_env_jobs, j, global_env_sle);
+ }
SLIST_INSERT_HEAD(&j->global_env, ei, sle);
} else {
SLIST_INSERT_HEAD(&j->env, ei, sle);
{
if (global) {
SLIST_REMOVE(&j->global_env, ei, envitem, sle);
+ if (SLIST_EMPTY(&j->global_env)) {
+ LIST_REMOVE(j, global_env_sle);
+ }
} else {
SLIST_REMOVE(&j->env, ei, envitem, sle);
}
return;
}
- envitem_new(j, key, launch_data_get_string(obj), j->importing_global_env);
+ 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);
+ }
+}
+
+void
+envitem_setup_one_shot(launch_data_t obj, const char *key, void *context)
+{
+ job_t j = context;
+
+ if (launch_data_get_type(obj) != LAUNCH_DATA_STRING) {
+ return;
+ }
+
+ 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);
+ }
}
bool
limititem_setup(launch_data_t obj, const char *key, void *context)
{
job_t j = context;
- int i, limits_cnt = (sizeof(launchd_keys2limits) / sizeof(launchd_keys2limits[0]));
+ size_t i, limits_cnt = (sizeof(launchd_keys2limits) / sizeof(launchd_keys2limits[0]));
rlim_t rl;
if (launch_data_get_type(obj) != LAUNCH_DATA_INTEGER) {
bool
job_useless(job_t j)
{
- /* Yes, j->unload_at_exit and j->only_once seem the same, but they'll differ someday... */
-
- if ((j->unload_at_exit || j->only_once) && j->start_time != 0) {
- if (j->unload_at_exit && j->j_port) {
+ if ((j->legacy_LS_job || j->only_once) && j->start_time != 0) {
+ if (j->legacy_LS_job && j->j_port) {
return false;
}
job_log(j, LOG_INFO, "Exited. Was only configured to run once.");
return true;
} else if (j->mgr->shutting_down && (j->hopefully_exits_first || j->mgr->hopefully_first_cnt == 0)) {
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");
+ }
return true;
} else if (j->legacy_mach_job) {
if (SLIST_EMPTY(&j->machservices)) {
struct machservice *ms;
struct stat sb;
bool good_exit = (WIFEXITED(j->last_exit_status) && WEXITSTATUS(j->last_exit_status) == 0);
+ bool is_not_kextd = (do_apple_internal_logging || (strcmp(j->label, "com.apple.kextd") != 0));
- if (j->mgr->shutting_down) {
+ if (unlikely(j->mgr->shutting_down)) {
return false;
}
* We definitely need to revisit this after Leopard ships. Please see
* launchctl.c for the other half of this hack.
*/
- if (j->mgr->global_on_demand_cnt > 0 && strcmp(j->label, "com.apple.kextd") != 0) {
+ if (unlikely((j->mgr->global_on_demand_cnt > 0) && is_not_kextd)) {
+ return false;
+ }
+
+ 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;
}
continue;
}
if (status.mps_msgcount) {
- job_log(j, LOG_DEBUG, "KeepAlive check: job restarted due to %d queued Mach messages on service: %s",
+ job_log(j, LOG_DEBUG, "KeepAlive check: %d queued Mach messages on service: %s",
status.mps_msgcount, ms->name);
return true;
}
wanted_state = true;
case PATH_MISSING:
if ((bool)(stat(si->what, &sb) == 0) == wanted_state) {
- if (si->fd != -1) {
- job_assumes(j, runtime_close(si->fd) == 0);
- si->fd = -1;
- }
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);
+ 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);
+ si->fd = -1;
+ semaphoreitem_watch(j, si);
+ }
+ }
}
break;
case PATH_CHANGES:
return false;
}
-const char *
-job_prog(job_t j)
-{
- if (j->prog) {
- return j->prog;
- } else if (j->argv) {
- return j->argv[0];
- } else {
- return "";
- }
-}
-
const char *
job_active(job_t j)
{
struct machservice *ms;
-
if (j->p) {
return "PID is still valid";
}
}
if (j->log_redirect_fd) {
- if (job_assumes(j, j->wait4pipe_eof)) {
+ 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);
}
SLIST_FOREACH(ms, &j->machservices, sle) {
- if (ms->recv && ms->isActive) {
+ if (ms->recv && machservice_active(ms)) {
return "Mach service is still active";
}
}
struct machservice *
machservice_new(job_t j, const char *name, mach_port_t *serviceport, bool pid_local)
{
- struct machservice *ms;
+ struct machservice *ms = calloc(1, sizeof(struct machservice) + strlen(name) + 1);
- if ((ms = calloc(1, sizeof(struct machservice) + strlen(name) + 1)) == NULL) {
+ if (!job_assumes(j, ms != NULL)) {
return NULL;
}
strcpy((char *)ms->name, name);
ms->job = j;
+ ms->gen_num = 1;
ms->per_pid = pid_local;
- if (*serviceport == MACH_PORT_NULL) {
+ if (likely(*serviceport == MACH_PORT_NULL)) {
if (!job_assumes(j, launchd_mport_create_recv(&ms->port) == KERN_SUCCESS)) {
goto out_bad;
}
}
SLIST_INSERT_HEAD(&j->machservices, ms, sle);
- LIST_INSERT_HEAD(&j->mgr->ms_hash[hash_ms(ms->name)], ms, name_hash_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;
+ }
+
+ LIST_INSERT_HEAD(&jm_to_insert->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_INFO, "Mach service added: %s", name);
+ job_log(j, LOG_DEBUG, "Mach service added%s: %s", (j->mgr->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) ? " to private namespace" : "", name);
return ms;
out_bad2:
thread_state_flavor_t f = 0;
mach_port_t exc_port = the_exception_server;
- if (j->alt_exc_handler) {
+ if (unlikely(j->alt_exc_handler)) {
ms = jobmgr_lookup_service(j->mgr, j->alt_exc_handler, true, 0);
- if (ms) {
+ if (likely(ms)) {
exc_port = machservice_port(ms);
} else {
job_log(j, LOG_WARNING, "Falling back to default Mach exception handler. Could not find: %s", j->alt_exc_handler);
}
- } else if (j->internal_exc_handler) {
+ } else if (unlikely(j->internal_exc_handler)) {
exc_port = runtime_get_kernel_port();
- } else if (!exc_port) {
+ } else if (unlikely(!exc_port)) {
return;
}
-#if defined (__ppc__) || defined (__ppc64__)
+#if defined (__ppc__) || defined(__ppc64__)
f = PPC_THREAD_STATE64;
#elif defined(__i386__) || defined(__x86_64__)
f = x86_THREAD_STATE;
#error "unknown architecture"
#endif
- if (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);
- } else if (getpid() == 1 && the_exception_server) {
+ 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);
+ } 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);
+ 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);
}
-
}
void
-job_set_exeception_port(job_t j, mach_port_t port)
+job_set_exception_port(job_t j, mach_port_t port)
{
- if (!the_exception_server) {
+ if (unlikely(!the_exception_server)) {
the_exception_server = port;
job_setup_exception_port(j, 0);
} else {
switch (launch_data_get_type(obj)) {
case LAUNCH_DATA_INTEGER:
- which_port = launch_data_get_integer(obj);
+ which_port = (int)launch_data_get_integer(obj); /* XXX we should bound check this... */
if (strcasecmp(key, LAUNCH_JOBKEY_MACH_TASKSPECIALPORT) == 0) {
switch (which_port) {
case TASK_KERNEL_PORT:
case TASK_HOST_PORT:
case TASK_NAME_PORT:
case TASK_BOOTSTRAP_PORT:
- /* I find it a little odd that zero isn't reserved in the header */
+ /* I find it a little odd that zero isn't reserved in the header.
+ * Normally Mach is fairly good about this convention... */
case 0:
job_log(ms->job, LOG_WARNING, "Tried to set a reserved task special port: %d", which_port);
break;
SLIST_INSERT_HEAD(&special_ports, ms, special_port_sle);
break;
}
- } else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_HOSTSPECIALPORT) == 0 && getpid() == 1) {
+ } 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);
} else {
} else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN) == 0) {
ms->hide = b;
} else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_EXCEPTIONSERVER) == 0) {
- job_set_exeception_port(ms->job, ms->port);
+ 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);
}
break;
+ case LAUNCH_DATA_STRING:
+ if( strcasecmp(key, LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH) == 0 ) {
+ const char *option = launch_data_get_string(obj);
+ if( strcasecmp(option, "One") == 0 ) {
+ ms->drain_one_on_crash = true;
+ } else if( strcasecmp(option, "All") == 0 ) {
+ ms->drain_all_on_crash = true;
+ }
+ }
+ break;
case LAUNCH_DATA_DICTIONARY:
- job_set_exeception_port(ms->job, ms->port);
+ job_set_exception_port(ms->job, ms->port);
break;
default:
break;
struct machservice *ms;
mach_port_t p = MACH_PORT_NULL;
- if ((ms = jobmgr_lookup_service(j->mgr, key, false, 0))) {
+ if (unlikely(ms = jobmgr_lookup_service(j->mgr, key, false, 0))) {
job_log(j, LOG_WARNING, "Conflict with job: %s over Mach service: %s", ms->job->label, key);
return;
}
- if ((ms = machservice_new(j, key, &p, false)) == NULL) {
- job_log_error(j, LOG_WARNING, "Cannot add service: %s", key);
+ if (!job_assumes(j, (ms = machservice_new(j, key, &p, false)) != NULL)) {
return;
}
jobmgr_t
jobmgr_do_garbage_collection(jobmgr_t jm)
{
- jobmgr_t jmi, jmn;
- job_t ji, jn;
-
+ jobmgr_t jmi = NULL, jmn = NULL;
SLIST_FOREACH_SAFE(jmi, &jm->submgrs, sle, jmn) {
jobmgr_do_garbage_collection(jmi);
}
- if (!jm->shutting_down) {
- return jm;
- }
-
- jobmgr_log(jm, LOG_DEBUG, "Garbage collecting.");
-
- /*
- * Normally, we wait for all resources of a job (Unix PIDs/FDs and Mach ports)
- * to reset before we conider the job truly dead and ready to be spawned again.
- *
- * In order to work around 5487724 and 3456090, we're going to call reboot()
- * when the last PID dies and not wait for the associated resources to reset.
- */
- if (getpid() == 1 && jm->parentmgr == NULL && total_children == 0) {
- jobmgr_log(jm, LOG_DEBUG, "About to force a call to: reboot(%s)", reboot_flags_to_C_names(jm->reboot_flags));
- runtime_closelog();
- jobmgr_assumes(jm, reboot(jm->reboot_flags) != -1);
- }
-
- if (jm->hopefully_first_cnt) {
+ if( !jm->shutting_down ) {
return jm;
}
-
- if (jm->parentmgr && jm->parentmgr->shutting_down && jm->parentmgr->hopefully_first_cnt) {
- return jm;
+
+ if( SLIST_EMPTY(&jm->submgrs) ) {
+ jobmgr_log(jm, LOG_DEBUG, "No submanagers left.");
+ } else {
+ jobmgr_log(jm, LOG_DEBUG, "Still have submanagers.");
}
-
- if (!jm->sent_stop_to_normal_jobs) {
- jobmgr_log(jm, LOG_DEBUG, "Asking \"normal\" jobs to exit.");
-
- LIST_FOREACH_SAFE(ji, &jm->jobs, sle, jn) {
- if (!job_active(ji)) {
- job_remove(ji);
- } else if (!ji->hopefully_exits_last) {
- job_stop(ji);
+
+ 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;
}
}
- jm->sent_stop_to_normal_jobs = true;
- }
-
- if (jm->normal_active_cnt) {
- return jm;
+ 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->migratory ) {
+ /* If we're shutting down, release the hold migratory 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;
+ }
+
+ const char *active = job_active(ji);
+ if( !active ) {
+ job_log(ji, LOG_DEBUG, "Job is inactive. Removing.");
+ job_remove(ji);
+ } 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);
+ }
+ }
+ } /* 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;
+ }
+ } /* for */
+
+ jobmgr_t r = jm;
+ if( jm->shutdown_phase > JOBMGR_PHASE_HOPEFULLY_EXITS_LAST && SLIST_EMPTY(&jm->submgrs) ) {
+ jobmgr_log(jm, LOG_DEBUG, "Removing.");
+ jobmgr_log_stray_children(jm, false);
+ jobmgr_remove(jm);
+ r = NULL;
}
+
+ return r;
+}
- if (!jm->sent_stop_to_hopefully_last_jobs) {
- jobmgr_log(jm, LOG_DEBUG, "Asking \"hopefully last\" jobs to exit.");
+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
+ * for them to exit before moving on.
+ *
+ * See rdar://problem/6562592
+ */
+ size_t 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_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;
+ }
- LIST_FOREACH(ji, &jm->jobs, sle) {
- if (ji->p && ji->anonymous) {
- continue;
- } else if (ji->p && job_assumes(ji, ji->hopefully_exits_last)) {
- job_stop(ji);
+ 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;
}
}
-
- jm->sent_stop_to_hopefully_last_jobs = true;
}
- if (!SLIST_EMPTY(&jm->submgrs)) {
- return jm;
+ 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];
+ }
}
- LIST_FOREACH(ji, &jm->jobs, sle) {
- if (!ji->anonymous) {
- return jm;
+ size_t n2k = 0;
+ for( i = 0; i < np; i++ ) {
+ if( p[i] != 0 ) {
+ jobmgr_assumes(jm, runtime_kill(p[i], SIGKILL) != -1);
+ n2k++;
}
}
- jobmgr_log_stray_children(jm);
- jobmgr_remove(jm);
- return NULL;
+ 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]);
+ }
+ }
+#endif
}
void
-jobmgr_log_stray_children(jobmgr_t jm)
+jobmgr_log_stray_children(jobmgr_t jm, bool kill_strays)
{
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
- size_t i, kp_cnt, len = sizeof(struct kinfo_proc) * get_kern_max_proc();
+ size_t i, kp_cnt = 0, kp_skipped = 0, len = sizeof(struct kinfo_proc) * get_kern_max_proc();
struct kinfo_proc *kp;
-#if TARGET_OS_EMBEDDED
- if (!do_apple_internal_magic) {
- return;
- }
-#endif
- if (jm->parentmgr || getpid() != 1) {
+ if (likely(jm->parentmgr || !pid1_magic)) {
return;
}
if (!jobmgr_assumes(jm, (kp = malloc(len)) != NULL)) {
return;
}
+
+ runtime_ktrace0(RTKT_LAUNCHD_FINDING_ALL_STRAYS);
+
if (!jobmgr_assumes(jm, sysctl(mib, 3, kp, &len, NULL, 0) != -1)) {
goto out;
}
kp_cnt = len / sizeof(struct kinfo_proc);
-
+ pid_t *ps = (pid_t *)calloc(sizeof(pid_t), kp_cnt);
+
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;
- if (p_i == 0 || p_i == 1) {
+ if (unlikely(p_i == 0 || p_i == 1)) {
+ 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);
+ 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;
+ if( pp_i == getpid() && !jobmgr_assumes(jm, kp[i].kp_proc.p_stat != 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++;
+ } else {
+ job_t leader = jobmgr_find_by_pid(jm, pg_i, false);
+ /* See rdar://problem/6745714. Some jobs have child processes that back kernel state,
+ * so we don't want to terminate them. Long-term, I'd really like to provide shutdown
+ * 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 ) {
+ kp_skipped++;
+ } else {
+ ps[i] = p_i;
+ }
+ }
+ } else {
+ kp_skipped++;
+ }
+ }
- jobmgr_log(jm, LOG_WARNING, "Stray %sprocess at shutdown: PID %u PPID %u PGID %u %s", z, p_i, pp_i, pg_i, n);
-
- /*
- * The kernel team requested that launchd not do this for Leopard.
- * jobmgr_assumes(jm, runtime_kill(p_i, SIGKILL) != -1);
- */
+ if( (kp_cnt - kp_skipped > 0) && kill_strays ) {
+ jobmgr_kill_stray_children(jm, ps, kp_cnt);
}
+ free(ps);
out:
free(kp);
}
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->forkfd, &c, sizeof(c)) == sizeof(c));
- job_assumes(j, runtime_close(j->forkfd) != -1);
- j->forkfd = 0;
+ job_assumes(j, write(j->fork_fd, &c, sizeof(c)) == sizeof(c));
+ job_assumes(j, runtime_close(j->fork_fd) != -1);
+ 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)
+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)
{
mach_msg_size_t mxmsgsz;
job_t bootstrapper = NULL;
launchd_assert(offsetof(struct jobmgr_s, kqjobmgr_callback) == 0);
- if (jm && requestorport == MACH_PORT_NULL) {
+ if (unlikely(jm && requestorport == MACH_PORT_NULL)) {
jobmgr_log(jm, LOG_ERR, "Mach sub-bootstrap create request requires a requester port");
return NULL;
}
- jmr = calloc(1, sizeof(struct jobmgr_s) + (name ? (strlen(name) + 1) : 128));
-
- if (jmr == NULL) {
+ jmr = calloc(1, sizeof(struct jobmgr_s) + (name ? (strlen(name) + 1) : NAME_MAX + 1));
+
+ if (!jobmgr_assumes(jm, jmr != NULL)) {
return NULL;
}
if (transfer_port != MACH_PORT_NULL) {
jobmgr_assumes(jmr, jm != NULL);
jmr->jm_port = transfer_port;
- } else if (!jm && getpid() != 1) {
+ } else if (!jm && !pid1_magic) {
char *trusted_fd = getenv(LAUNCHD_TRUSTED_FD_ENV);
name_t service_buf;
}
if (trusted_fd) {
- int dfd, lfd = strtol(trusted_fd, NULL, 10);
+ int dfd, lfd = (int) strtol(trusted_fd, NULL, 10);
if ((dfd = dup(lfd)) >= 0) {
jobmgr_assumes(jmr, runtime_close(dfd) != -1);
}
/* Sigh... at the moment, MIG has maxsize == sizeof(reply union) */
- mxmsgsz = sizeof(union __RequestUnion__job_mig_protocol_vproc_subsystem);
+ mxmsgsz = (typeof(mxmsgsz)) sizeof(union __RequestUnion__job_mig_protocol_vproc_subsystem);
if (job_mig_protocol_vproc_subsystem.maxsize > mxmsgsz) {
mxmsgsz = job_mig_protocol_vproc_subsystem.maxsize;
}
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);
}
- if (name) {
+ if (name && !no_init) {
bootstrapper = jobmgr_init_session(jmr, name, sflag);
}
}
}
+ STAILQ_INIT(&jmr->pending_samples);
+
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);
+ }
+
+ jobmgr_log(jmr, LOG_DEBUG, "Bootstrapping new job manager with audit session %u", session_port);
jobmgr_assumes(jmr, job_dispatch(bootstrapper, true) != NULL);
}
if (jmr->parentmgr) {
- runtime_add_ref();
+ runtime_add_weak_ref();
}
return jmr;
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 || getuid())) {
+
+ if( jobmgr_assumes(jm, bootstrapper != NULL) && (jm->parentmgr || !pid1_magic) ) {
+ bootstrapper->is_bootstrapper = true;
char buf[100];
/* <rdar://problem/5042202> launchd-201: can't ssh in with AFP OD account (hangs) */
snprintf(buf, sizeof(buf), "0x%X:0:0", getuid());
- envitem_new(bootstrapper, "__CF_USER_TEXT_ENCODING", buf, false);
+ 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 ) {
+ bootstrapper->is_bootstrapper = true;
+ 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);
+
+ if( g_console ) {
+ 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;
if (jm == root_jobmgr) {
if (port == inherited_bootstrap_port) {
- launchd_assumes(launchd_mport_deallocate(port) == KERN_SUCCESS);
+ jobmgr_assumes(jm, launchd_mport_deallocate(port) == KERN_SUCCESS);
inherited_bootstrap_port = MACH_PORT_NULL;
return jobmgr_shutdown(jm);
}
LIST_FOREACH_SAFE(ms, &port_hash[HASH_PORT(port)], port_hash_sle, next_ms) {
- if (ms->port == port) {
+ if (ms->port == port && !ms->recv) {
machservice_delete(ms->job, ms, true);
}
}
}
if (jm->req_port == port) {
- jobmgr_log(jm, LOG_DEBUG, "Request port died: 0x%x", port);
+ jobmgr_log(jm, LOG_DEBUG, "Request port died: %i", MACH_PORT_INDEX(port));
return jobmgr_shutdown(jm);
}
jobmgr_lookup_service(jobmgr_t jm, const char *name, bool check_parent, pid_t target_pid)
{
struct machservice *ms;
+ job_t target_j;
- if (target_pid) {
- jobmgr_assumes(jm, !check_parent);
- }
+ jobmgr_log(jm, LOG_DEBUG, "Looking up %sservice %s", target_pid ? "per-PID " : "", name);
- LIST_FOREACH(ms, &jm->ms_hash[hash_ms(name)], name_hash_sle) {
- if ((target_pid && ms->per_pid && ms->job->p == target_pid) || (!target_pid && !ms->per_pid)) {
- if (strcmp(name, ms->name) == 0) {
+ if (target_pid) {
+ /* This is a hack to let FileSyncAgent look up per-PID Mach services from the Background
+ * bootstrap in other bootstraps.
+ */
+
+ /* Start in the given bootstrap. */
+ 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);
+ return NULL;
+ }
+ }
+
+ SLIST_FOREACH(ms, &target_j->machservices, sle) {
+ if (ms->per_pid && strcmp(name, ms->name) == 0) {
return ms;
}
}
- }
- if (jm->parentmgr == NULL) {
+ job_log(target_j, LOG_DEBUG, "Didn't find per-PID Mach service: %s", name);
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;
+ }
+ }
- if (!check_parent) {
+ if (jm->parentmgr == NULL || !check_parent) {
return NULL;
}
return ms->name;
}
+void
+machservice_drain_port(struct machservice *ms)
+{
+ 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) ) {
+ return;
+ }
+
+ job_log(ms->job, LOG_INFO, "Draining %s...", ms->name);
+
+ char req_buff[sizeof(union __RequestUnion__catch_mach_exc_subsystem) * 2];
+ char rep_buff[sizeof(union __ReplyUnion__catch_mach_exc_subsystem)];
+ mig_reply_error_t *req_hdr = (mig_reply_error_t *)&req_buff;
+ mig_reply_error_t *rep_hdr = (mig_reply_error_t *)&rep_buff;
+
+ mach_msg_return_t mr = ~MACH_MSG_SUCCESS;
+
+ do {
+ /* This should be a direct check on the Mach service to see if it's an exception-handling
+ * 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 ) {
+ 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;
+ }
+ }
+ } while( drain_all && mr != MACH_RCV_TIMED_OUT );
+}
+
void
machservice_delete(job_t j, struct machservice *ms, bool port_died)
{
- if (ms->debug_on_close) {
+ 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);
}
- if (ms->recv && job_assumes(j, !ms->isActive)) {
+ 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);
}
job_assumes(j, launchd_mport_deallocate(ms->port) == KERN_SUCCESS);
- if (ms->port == the_exception_server) {
+ if (unlikely(ms->port == the_exception_server)) {
the_exception_server = 0;
}
- job_log(j, LOG_INFO, "Mach service deleted%s: %s", port_died ? " (port died)" : "", ms->name);
+ job_log(j, LOG_DEBUG, "Mach service deleted%s: %s", port_died ? " (port died)" : "", ms->name);
if (ms->special_port_num) {
SLIST_REMOVE(&special_ports, ms, machservice, special_port_sle);
j->checkedin = true;
}
+bool job_is_god(job_t j)
+{
+ return j->embedded_special_privileges;
+}
+
bool
job_ack_port_destruction(mach_port_t p)
{
struct machservice *ms;
+ job_t j;
LIST_FOREACH(ms, &port_hash[HASH_PORT(p)], port_hash_sle) {
if (ms->recv && (ms->port == p)) {
}
}
- if (!ms) {
+ if (!jobmgr_assumes(root_jobmgr, ms != NULL)) {
return false;
}
- ms->isActive = false;
+ j = ms->job;
- if (ms->reset) {
- machservice_resetport(ms->job, ms);
+ jobmgr_log(root_jobmgr, LOG_DEBUG, "Receive right returned to us: %s", ms->name);
+
+ /* Without being the exception handler, NOTE_EXIT is our only way to tell if the job
+ * crashed, and we can't rely on NOTE_EXIT always being processed after all the job's
+ * receive rights have been returned.
+ *
+ * So when we get receive rights back, check to see if the job has been reaped yet. If
+ * not, then we add this service to a list of services to be drained on crash if it's
+ * requested that behavior. So, for a job with N receive rights all requesting that they
+ * be drained on crash, we can safely handle the following sequence of events.
+ *
+ * ReceiveRight0Returned
+ * ReceiveRight1Returned
+ * ReceiveRight2Returned
+ * NOTE_EXIT (reap, get exit status)
+ * ReceiveRight3Returned
+ * .
+ * .
+ * .
+ * ReceiveRight(N - 1)Returned
+ */
+
+ 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);
+ } else if( !(j->crashed || j->reaped) ) {
+ job_log(j, LOG_DEBUG, "Job's exit status is still unknown. Deferring drain.");
+ }
}
-
- job_log(ms->job, LOG_DEBUG, "Receive right returned to us: %s", ms->name);
- job_dispatch(ms->job, false);
+
+ ms->isActive = false;
+ if (ms->delete_on_destruction) {
+ machservice_delete(j, ms, false);
+ } else if (ms->reset) {
+ machservice_resetport(j, ms);
+ }
+
+ job_dispatch(j, false);
root_jobmgr = jobmgr_do_garbage_collection(root_jobmgr);
job_dispatch(j, false);
}
-jobmgr_t
-job_get_bs(job_t j)
-{
- if (job_assumes(j, j->mgr != NULL)) {
- return j->mgr;
- }
-
- return NULL;
-}
-
-bool
-job_is_anonymous(job_t j)
-{
- return j->anonymous;
-}
-
-void
-job_force_sampletool(job_t j)
-{
- struct stat sb;
- char logfile[PATH_MAX];
- char pidstr[100];
- char *sample_args[] = { "sample", pidstr, "1", "-mayDie", "-file", logfile, NULL };
- char *contents = NULL;
- int logfile_fd = -1;
- int console_fd = -1;
- int wstatus;
- pid_t sp;
-
- if (!debug_shutdown_hangs) {
- return;
- }
-
- snprintf(pidstr, sizeof(pidstr), "%u", j->p);
- snprintf(logfile, sizeof(logfile), SHUTDOWN_LOG_DIR "/%s-%u.sample.txt", j->label, j->p);
-
- if (!job_assumes(j, unlink(logfile) != -1 || errno == ENOENT)) {
- goto out;
- }
-
- /*
- * This will stall launchd for as long as the 'sample' tool runs.
- *
- * We didn't give the 'sample' tool a bootstrap port, so it therefore
- * can't deadlock against launchd.
- */
- if (!job_assumes(j, (errno = posix_spawnp(&sp, sample_args[0], NULL, NULL, sample_args, environ)) == 0)) {
- goto out;
- }
-
- job_log(j, LOG_DEBUG, "Waiting for 'sample' to finish.");
-
- if (!job_assumes(j, waitpid(sp, &wstatus, 0) != -1)) {
- goto out;
- }
-
- /*
- * This won't work if the VFS or filesystems are sick:
- * sync();
- */
-
- if (!job_assumes(j, WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0)) {
- goto out;
- }
-
- if (!job_assumes(j, (logfile_fd = open(logfile, O_RDONLY|O_NOCTTY)) != -1)) {
- goto out;
- }
-
- if (!job_assumes(j, (console_fd = open(_PATH_CONSOLE, O_WRONLY|O_APPEND|O_NOCTTY)) != -1)) {
- goto out;
- }
-
- if (!job_assumes(j, fstat(logfile_fd, &sb) != -1)) {
- goto out;
- }
-
- contents = malloc(sb.st_size);
-
- if (!job_assumes(j, contents != NULL)) {
- goto out;
- }
-
- if (!job_assumes(j, read(logfile_fd, contents, sb.st_size) == sb.st_size)) {
- goto out;
- }
-
- job_assumes(j, write(console_fd, contents, sb.st_size) == sb.st_size);
-
-out:
- if (contents) {
- free(contents);
- }
-
- if (logfile_fd != -1) {
- job_assumes(j, runtime_fsync(logfile_fd) != -1);
- job_assumes(j, runtime_close(logfile_fd) != -1);
- }
-
- if (console_fd != -1) {
- job_assumes(j, runtime_close(console_fd) != -1);
- }
-
- job_log(j, LOG_DEBUG, "Finished sampling.");
-}
-
bool
semaphoreitem_new(job_t j, semaphore_reason_t why, const char *what)
{
}
SLIST_INSERT_HEAD(&j->semaphores, si, sle);
+
+ 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;
+ }
semaphoreitem_runtime_mod_ref(si, true);
}
if (add) {
- runtime_add_ref();
+ runtime_add_weak_ref();
} else {
- runtime_del_ref();
+ runtime_del_weak_ref();
}
}
if (si->fd != -1) {
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. */
+ 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);
+ }
free(si);
}
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 ) {
+ j->needs_kickoff = launch_data_get_bool(obj);
} else {
job_assumes(j, false);
}
return true;
}
+kern_return_t
+job_mig_setup_shmem(job_t j, mach_port_t *shmem_port)
+{
+ memory_object_size_t size_of_page, size_of_page_orig;
+ vm_address_t vm_addr;
+ kern_return_t kr;
+
+ if (!launchd_assumes(j != NULL)) {
+ return BOOTSTRAP_NO_MEMORY;
+ }
+
+ if (unlikely(j->anonymous)) {
+ job_log(j, LOG_DEBUG, "Anonymous job tried to setup shared memory");
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+
+ if (unlikely(j->shmem)) {
+ job_log(j, LOG_ERR, "Tried to setup shared memory more than once");
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+
+ size_of_page_orig = size_of_page = getpagesize();
+
+ kr = vm_allocate(mach_task_self(), &vm_addr, size_of_page, true);
+
+ if (!job_assumes(j, kr == 0)) {
+ return kr;
+ }
+
+ j->shmem = (typeof(j->shmem))vm_addr;
+ j->shmem->vp_shmem_standby_timeout = j->timeout;
+
+ kr = mach_make_memory_entry_64(mach_task_self(), &size_of_page,
+ (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);
+ }
+
+ /* 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);
+
+ return kr;
+}
+
kern_return_t
job_mig_create_server(job_t j, cmd_t server_cmd, uid_t server_uid, boolean_t on_demand, mach_port_t *server_portp)
{
- struct ldcred ldc;
+ struct ldcred *ldc = runtime_get_caller_creds();
job_t js;
-#if TARGET_OS_EMBEDDED
- return BOOTSTRAP_NOT_PRIVILEGED;
-#endif
-
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
return BOOTSTRAP_NOT_PRIVILEGED;
}
- runtime_get_caller_creds(&ldc);
+#if HAVE_SANDBOX
+ const char **argv = (const char **)mach_cmd2argv(server_cmd);
+ if (unlikely(argv == NULL)) {
+ return BOOTSTRAP_NO_MEMORY;
+ }
+ if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_PATH, argv[0]) > 0)) {
+ free(argv);
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+ free(argv);
+#endif
job_log(j, LOG_DEBUG, "Server create attempt: %s", server_cmd);
-#define LET_MERE_MORTALS_ADD_SERVERS_TO_PID1
- /* XXX - This code should go away once the per session launchd is integrated with the rest of the system */
-#ifdef LET_MERE_MORTALS_ADD_SERVERS_TO_PID1
- if (getpid() == 1) {
- if (ldc.euid && server_uid && (ldc.euid != server_uid)) {
- job_log(j, LOG_WARNING, "Server create: \"%s\": Will run as UID %d, not UID %d as they told us to",
- server_cmd, ldc.euid, server_uid);
- server_uid = ldc.euid;
+ if (pid1_magic) {
+ if (ldc->euid || ldc->uid) {
+ job_log(j, LOG_WARNING, "Server create attempt moved to per-user launchd: %s", server_cmd);
+ return VPROC_ERR_TRY_PER_USER;
}
- } else
-#endif
- if (getuid()) {
- if (server_uid != getuid()) {
+ } else {
+ if (unlikely(server_uid != getuid())) {
job_log(j, LOG_WARNING, "Server create: \"%s\": As UID %d, we will not be able to switch to UID %d",
server_cmd, getuid(), server_uid);
}
js = job_new_via_mach_init(j, server_cmd, server_uid, on_demand);
- if (js == NULL) {
+ if (unlikely(js == NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
kern_return_t
job_mig_send_signal(job_t j, mach_port_t srp, name_t targetlabel, int sig)
{
- struct ldcred ldc;
+ struct ldcred *ldc = runtime_get_caller_creds();
job_t otherj;
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
- runtime_get_caller_creds(&ldc);
+ if( unlikely(ldc->euid != 0 && ldc->euid != getuid()) || j->deny_job_creation ) {
+
+ }
- if (ldc.euid != 0 && ldc.euid != getuid()) {
+ if( unlikely(ldc->euid != 0 && ldc->euid != getuid()) || j->deny_job_creation ) {
+ #if TARGET_OS_EMBEDDED
+ if( !j->embedded_special_privileges ) {
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+ #else
return BOOTSTRAP_NOT_PRIVILEGED;
+ #endif
}
- if (!(otherj = job_find(targetlabel))) {
+#if HAVE_SANDBOX
+ if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+#endif
+
+ if (unlikely(!(otherj = job_find(targetlabel)))) {
return BOOTSTRAP_UNKNOWN_SERVICE;
}
- if (sig == VPROC_MAGIC_UNLOAD_SIGNAL) {
- bool do_block = otherj->p;
-
+#if TARGET_OS_EMBEDDED
+ if( j->embedded_special_privileges && strcmp(j->username, otherj->username) != 0 ) {
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+#endif
+
+ if (sig == VPROC_MAGIC_UNLOAD_SIGNAL) {
+ bool do_block = otherj->p;
+
if (otherj->anonymous) {
return BOOTSTRAP_NOT_PRIVILEGED;
}
} else {
return 0;
}
+ } else if (sig == VPROC_MAGIC_TRYKILL_SIGNAL) {
+ if (!j->kill_via_shmem) {
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+
+ if (!j->shmem) {
+ j->sent_kill_via_shmem = true;
+ job_assumes(j, runtime_kill(otherj->p, SIGKILL) != -1);
+ return 0;
+ }
+ #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;
+ job_assumes(j, runtime_kill(otherj->p, SIGKILL) != -1);
+ return 0;
+ }
+ #endif
+ return BOOTSTRAP_NOT_PRIVILEGED;
} else if (otherj->p) {
job_assumes(j, runtime_kill(otherj->p, sig) != -1);
}
kern_return_t
job_mig_log_forward(job_t j, vm_offset_t inval, mach_msg_type_number_t invalCnt)
{
- struct ldcred ldc;
+ struct ldcred *ldc = runtime_get_caller_creds();
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
return BOOTSTRAP_NOT_PRIVILEGED;
}
- runtime_get_caller_creds(&ldc);
-
- return runtime_log_forward(ldc.euid, ldc.egid, inval, invalCnt);
+ return runtime_log_forward(ldc->euid, ldc->egid, inval, invalCnt);
}
kern_return_t
job_mig_log_drain(job_t j, mach_port_t srp, vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
{
- struct ldcred ldc;
+ struct ldcred *ldc = runtime_get_caller_creds();
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
- runtime_get_caller_creds(&ldc);
-
- if (ldc.euid) {
+ if (unlikely(ldc->euid)) {
return BOOTSTRAP_NOT_PRIVILEGED;
}
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)
+ 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, output_obj;
+ launch_data_t input_obj = NULL, output_obj = NULL;
size_t data_offset = 0;
size_t packed_size;
- struct ldcred ldc;
-
- runtime_get_caller_creds(&ldc);
+ struct ldcred *ldc = runtime_get_caller_creds();
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
- if (inkey && ldc.euid && ldc.euid != getuid()) {
+ if (unlikely(inkey && ldc->euid && ldc->euid != getuid())) {
return BOOTSTRAP_NOT_PRIVILEGED;
}
- if (inkey && outkey && !job_assumes(j, inkey == outkey)) {
+ if (unlikely(inkey && outkey && !job_assumes(j, inkey == outkey))) {
return 1;
}
return 1;
}
- if (invalCnt && !job_assumes(j, (input_obj = launch_data_unpack((void *)inval, invalCnt, NULL, 0, &data_offset, NULL)) != NULL)) {
+ 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;
}
goto out_bad;
}
jobmgr_export_env_from_other_jobs(j->mgr, output_obj);
+ runtime_ktrace0(RTKT_LAUNCHD_DATA_PACK);
if (!job_assumes(j, launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL) != 0)) {
goto out_bad;
}
goto out_bad;
}
ipc_revoke_fds(output_obj);
+ runtime_ktrace0(RTKT_LAUNCHD_DATA_PACK);
+ 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_MGR_NAME:
+ 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;
+ }
+
+ 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) ) {
+ 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_CACHE_DB:
+ 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);
if (!job_assumes(j, packed_size != 0)) {
goto out_bad;
}
+
+ 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:
}
if (invalCnt) switch (inkey) {
- case VPROC_GSK_ENVIRONMENT:
- job_assumes(j, false);
+ 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);
+ }
break;
case 0:
break;
{
const char *action;
kern_return_t kr = 0;
- struct ldcred ldc;
+ struct ldcred *ldc = runtime_get_caller_creds();
int oldmask;
- runtime_get_caller_creds(&ldc);
-
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
- if (inkey && ldc.euid && ldc.euid != getuid()) {
+ if (unlikely(inkey && ldc->euid && ldc->euid != getuid())) {
return BOOTSTRAP_NOT_PRIVILEGED;
}
- if (inkey && outkey && !job_assumes(j, inkey == outkey)) {
+ if (unlikely(inkey && outkey && !job_assumes(j, inkey == outkey))) {
return 1;
}
job_log(j, LOG_DEBUG, "%s key: %u", action, inkey ? inkey : outkey);
switch (outkey) {
+ case VPROC_GSK_ABANDON_PROCESS_GROUP:
+ *outval = j->abandon_pg;
+ break;
case VPROC_GSK_LAST_EXIT_STATUS:
*outval = j->last_exit_status;
break;
*outval = oldmask;
umask(oldmask);
break;
+ case VPROC_GSK_TRANSACTIONS_ENABLED:
+ job_log(j, LOG_DEBUG, "Reading transaction model status.");
+ *outval = j->kill_via_shmem;
+ break;
+ case VPROC_GSK_WAITFORDEBUGGER:
+ *outval = j->wait4debugger;
+ break;
+ case VPROC_GSK_EMBEDDEDROOTEQUIVALENT:
+ *outval = j->embedded_special_privileges;
+ break;
case 0:
*outval = 0;
break;
}
switch (inkey) {
+ case VPROC_GSK_ABANDON_PROCESS_GROUP:
+ j->abandon_pg = (bool)inval;
+ break;
case VPROC_GSK_GLOBAL_ON_DEMAND:
+ job_log(j, LOG_DEBUG, "Job is setting global on-demand mode to %s (j->forced_peers_to_demand_mode = %s)", (bool)inval ? "true" : "false", j->forced_peers_to_demand_mode ? "true" : "false");
kr = job_set_global_on_demand(j, (bool)inval) ? 0 : 1;
break;
case VPROC_GSK_BASIC_KEEPALIVE:
j->ondemand = !inval;
break;
case VPROC_GSK_START_INTERVAL:
- if ((uint64_t)inval > UINT32_MAX) {
+ if (inval > UINT32_MAX || inval < 0) {
kr = 1;
} else if (inval) {
if (j->start_interval == 0) {
- runtime_add_ref();
- } else {
- /* Workaround 5225889 */
- job_assumes(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_DELETE, 0, 0, j) != -1);
+ runtime_add_weak_ref();
}
- j->start_interval = inval;
+ 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);
} else if (j->start_interval) {
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_ref();
+ runtime_del_weak_ref();
}
j->start_interval = 0;
}
break;
case VPROC_GSK_IDLE_TIMEOUT:
- if ((unsigned int)inval > 0) {
- j->timeout = inval;
+ if (inval < 0 || inval > UINT32_MAX) {
+ kr = 1;
+ } else {
+ j->timeout = (typeof(j->timeout)) inval;
}
break;
case VPROC_GSK_EXIT_TIMEOUT:
- if ((unsigned int)inval > 0) {
- j->exit_timeout = inval;
+ if (inval < 0 || inval > UINT32_MAX) {
+ kr = 1;
+ } else {
+ j->exit_timeout = (typeof(j->exit_timeout)) inval;
}
break;
case VPROC_GSK_GLOBAL_LOG_MASK:
- runtime_setlogmask(inval);
+ if (inval < 0 || inval > UINT32_MAX) {
+ kr = 1;
+ } else {
+ runtime_setlogmask((int) inval);
+ }
break;
case VPROC_GSK_GLOBAL_UMASK:
- umask(inval);
+ launchd_assert(sizeof (mode_t) == 2);
+ if (inval < 0 || inval > UINT16_MAX) {
+ kr = 1;
+ } else {
+ umask((mode_t) inval);
+ }
+ break;
+ case VPROC_GSK_TRANSACTIONS_ENABLED:
+ 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_DEBUG, "Now participating in transaction model.");
+ 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:
+ 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);
+
+ if (job_mig_protocol_vproc_subsystem.maxsize > mxmsgsz) {
+ mxmsgsz = job_mig_protocol_vproc_subsystem.maxsize;
+ }
+
+ job_assumes(j, runtime_add_mport(j->mgr->jm_port, protocol_vproc_server, mxmsgsz) == KERN_SUCCESS);
+ j->weird_bootstrap = false;
+ }
+ break;
+ case VPROC_GSK_WAITFORDEBUGGER:
+ j->wait4debugger_oneshot = inval;
+ break;
+ case VPROC_GSK_PERUSER_SUSPEND:
+ if( job_assumes(j, pid1_magic && ldc->euid == 0) ) {
+ 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) ) {
+ struct suspended_peruser *spi = NULL;
+ 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;
+ }
+ }
+
+ 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);
+ if( job_assumes(j, spi != NULL) ) {
+ spi->j = jpu;
+ spi->j->peruser_suspend_count++;
+ LIST_INSERT_HEAD(&j->suspended_perusers, spi, sle);
+ job_stop(spi->j);
+ } else {
+ kr = BOOTSTRAP_NO_MEMORY;
+ }
+ }
+ }
+ } else {
+ kr = 1;
+ }
+ break;
+ case VPROC_GSK_PERUSER_RESUME:
+ if( job_assumes(j, pid1_magic == true) ) {
+ struct suspended_peruser *spi = NULL, *spt = NULL;
+ 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);
+ break;
+ }
+ }
+
+ 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;
+ } else if( spi->j->peruser_suspend_count == 0 ) {
+ job_dispatch(spi->j, false);
+ free(spi);
+ }
+ } else {
+ kr = 1;
+ }
break;
case 0:
break;
}
kern_return_t
-job_mig_post_fork_ping(job_t j, task_t child_task)
+job_mig_post_fork_ping(job_t j, task_t child_task, mach_port_t *audit_session)
{
struct machservice *ms;
errno = task_set_special_port(child_task, ms->special_port_num, ms->port);
- if (errno) {
+ if (unlikely(errno)) {
int desired_log_level = LOG_ERR;
if (j->anonymous) {
}
}
+ mach_port_t _session = MACH_PORT_NULL;
+#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;
+ }
+#endif
+ *audit_session = _session;
job_assumes(j, launchd_mport_deallocate(child_task) == KERN_SUCCESS);
return 0;
{
char who_started_the_reboot[2048] = "";
struct kinfo_proc kp;
- struct ldcred ldc;
+ struct ldcred *ldc = runtime_get_caller_creds();
pid_t pid_to_log;
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
- if (getpid() != 1) {
+ if (unlikely(!pid1_magic)) {
return BOOTSTRAP_NOT_PRIVILEGED;
}
- runtime_get_caller_creds(&ldc);
-
- if (ldc.euid) {
+#if !TARGET_OS_EMBEDDED
+ if (unlikely(ldc->euid)) {
+#else
+ if( unlikely(ldc->euid) && !j->embedded_special_privileges ) {
+#endif
return BOOTSTRAP_NOT_PRIVILEGED;
}
- for (pid_to_log = ldc.pid; pid_to_log; pid_to_log = kp.kp_eproc.e_ppid) {
+ 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);
return BOOTSTRAP_NO_MEMORY;
}
+ if( j->deny_job_creation ) {
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+
ipc_server_init();
- if (!sockpath) {
+ if (unlikely(!sockpath)) {
return BOOTSTRAP_NO_MEMORY;
}
return 0;
}
-void
-ensure_root_bkgd_setup(void)
-{
- if (background_jobmgr || getpid() != 1) {
- return;
- }
-
- if (!jobmgr_assumes(root_jobmgr, (background_jobmgr = jobmgr_new(root_jobmgr, mach_task_self(), MACH_PORT_NULL, false, VPROCMGR_SESSION_BACKGROUND)) != NULL)) {
- return;
- }
-
- background_jobmgr->req_port = 0;
- jobmgr_assumes(root_jobmgr, launchd_mport_make_send(background_jobmgr->jm_port) == KERN_SUCCESS);
-}
-
-kern_return_t
-job_mig_lookup_per_user_context(job_t j, uid_t which_user, mach_port_t *up_cont)
+job_t
+jobmgr_lookup_per_user_context_internal(job_t j, uid_t which_user, bool dispatch, mach_port_t *mp)
{
- struct ldcred ldc;
- job_t ji;
-
-#if TARGET_OS_EMBEDDED
- return BOOTSTRAP_NOT_PRIVILEGED;
-#endif
-
- if (!launchd_assumes(j != NULL)) {
- return BOOTSTRAP_NO_MEMORY;
- }
-
- job_log(j, LOG_DEBUG, "Looking up per user launchd for UID: %u", which_user);
-
- runtime_get_caller_creds(&ldc);
-
- if (getpid() != 1) {
- job_log(j, LOG_ERR, "Only PID 1 supports per user launchd lookups.");
- return BOOTSTRAP_NOT_PRIVILEGED;
- }
-
- if (ldc.euid || ldc.uid) {
- which_user = ldc.euid ? ldc.euid : ldc.uid;
- }
-
- *up_cont = MACH_PORT_NULL;
-
- if (which_user == 0) {
- ensure_root_bkgd_setup();
-
- *up_cont = background_jobmgr->jm_port;
-
- return 0;
- }
-
+ job_t ji = NULL;
LIST_FOREACH(ji, &root_jobmgr->jobs, sle) {
if (!ji->per_user) {
continue;
}
break;
}
-
- if (ji == NULL) {
+
+ if( unlikely(ji == NULL) ) {
struct machservice *ms;
char lbuf[1024];
-
+
job_log(j, LOG_DEBUG, "Creating per user launchd job for UID: %u", which_user);
-
+
sprintf(lbuf, "com.apple.launchd.peruser.%u", which_user);
-
+
ji = job_new(root_jobmgr, lbuf, "/sbin/launchd", NULL);
+
+ if( ji != NULL ) {
+ 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);
+ 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);
+
+ job_assumes(ji, rename(pu_db, move_aside) != -1);
+ }
- if (ji == NULL) {
- return BOOTSTRAP_NO_MEMORY;
- }
-
- ji->mach_uid = which_user;
- ji->per_user = true;
-
- if ((ms = machservice_new(ji, lbuf, up_cont, false)) == NULL) {
- job_remove(ji);
- return BOOTSTRAP_NO_MEMORY;
+ job_assumes(ji, mkdir(pu_db, S_IRWXU) != -1);
+ job_assumes(ji, chown(pu_db, which_user, 0) != -1);
+ created = true;
+ }
+
+ if( !created ) {
+ if( !job_assumes(ji, sb.st_uid == which_user) ) {
+ 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_mode == (S_IRWXU | S_IFDIR)) ) {
+ job_assumes(ji, chmod(pu_db, S_IRWXU) != -1);
+ }
+ }
+
+ if ((ms = machservice_new(ji, lbuf, mp, false)) == NULL) {
+ job_remove(ji);
+ ji = NULL;
+ } else {
+ ms->per_user_hack = true;
+ ms->hide = true;
+
+ ji = dispatch ? job_dispatch(ji, false) : ji;
+ }
}
-
- ms->per_user_hack = true;
- ms->hide = true;
-
- ji = job_dispatch(ji, false);
} else {
+ *mp = machservice_port(SLIST_FIRST(&ji->machservices));
job_log(j, LOG_DEBUG, "Per user launchd job found for UID: %u", which_user);
}
+
+ return ji;
+}
- if (job_assumes(j, ji != NULL)) {
- *up_cont = machservice_port(SLIST_FIRST(&ji->machservices));
+kern_return_t
+job_mig_lookup_per_user_context(job_t j, uid_t which_user, mach_port_t *up_cont)
+{
+ struct ldcred *ldc = runtime_get_caller_creds();
+ job_t jpu;
+
+#if TARGET_OS_EMBEDDED
+ /* There is no need for per-user launchd's on embedded. */
+ job_log(j, LOG_ERR, "Per-user launchds are not supported on this platform.");
+ return BOOTSTRAP_NOT_PRIVILEGED;
+#endif
+
+#if HAVE_SANDBOX
+ if (unlikely(sandbox_check(ldc->pid, "mach-per-user-lookup", SANDBOX_FILTER_NONE) > 0)) {
+ return BOOTSTRAP_NOT_PRIVILEGED;
}
-
+#endif
+
+ if (!launchd_assumes(j != NULL)) {
+ return BOOTSTRAP_NO_MEMORY;
+ }
+
+ job_log(j, LOG_INFO, "Looking up per user launchd for UID: %u", which_user);
+
+ if (unlikely(!pid1_magic)) {
+ job_log(j, LOG_ERR, "Only PID 1 supports per user launchd lookups.");
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+
+ if (ldc->euid || ldc->uid) {
+ which_user = ldc->euid ?: ldc->uid;
+ }
+
+ *up_cont = MACH_PORT_NULL;
+
+ jpu = jobmgr_lookup_per_user_context_internal(j, which_user, true, up_cont);
+
return 0;
}
kern_return_t
-job_mig_check_in(job_t j, name_t servicename, mach_port_t *serviceportp)
+job_mig_check_in2(job_t j, name_t servicename, mach_port_t *serviceportp, uint64_t flags)
{
- static pid_t last_warned_pid = 0;
+ bool per_pid_service = flags & BOOTSTRAP_PER_PID_SERVICE;
+ struct ldcred *ldc = runtime_get_caller_creds();
struct machservice *ms;
- struct ldcred ldc;
+ job_t jo;
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
- runtime_get_caller_creds(&ldc);
-
- ms = jobmgr_lookup_service(j->mgr, servicename, true, 0);
+ ms = jobmgr_lookup_service(j->mgr, servicename, false, per_pid_service ? ldc->pid : 0);
if (ms == NULL) {
- job_log(j, LOG_DEBUG, "Check-in of Mach service failed. Unknown: %s", servicename);
- return BOOTSTRAP_UNKNOWN_SERVICE;
- }
- if (machservice_job(ms) != j) {
- if (last_warned_pid != ldc.pid) {
- job_log(j, LOG_NOTICE, "Check-in of Mach service failed. PID %d is not privileged: %s",
- ldc.pid, servicename);
- last_warned_pid = ldc.pid;
+ *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 {
+ if (unlikely((jo = machservice_job(ms)) != j)) {
+ static pid_t last_warned_pid;
+
+ if (last_warned_pid != ldc->pid) {
+ job_log(jo, LOG_WARNING, "The following job tried to hijack the service \"%s\" from this job: %s", servicename, j->label);
+ last_warned_pid = ldc->pid;
+ }
+
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+ if (unlikely(machservice_active(ms))) {
+ job_log(j, LOG_WARNING, "Check-in of Mach service failed. Already active: %s", servicename);
+ return BOOTSTRAP_SERVICE_ACTIVE;
}
- return BOOTSTRAP_NOT_PRIVILEGED;
- }
- if (machservice_active(ms)) {
- job_log(j, LOG_WARNING, "Check-in of Mach service failed. Already active: %s", servicename);
- return BOOTSTRAP_SERVICE_ACTIVE;
}
+ job_checkin(j);
machservice_request_notifications(ms);
job_log(j, LOG_INFO, "Check-in of service: %s", servicename);
job_mig_register2(job_t j, name_t servicename, mach_port_t serviceport, uint64_t flags)
{
struct machservice *ms;
- struct ldcred ldc;
+ struct ldcred *ldc = runtime_get_caller_creds();
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
- runtime_get_caller_creds(&ldc);
-
-#if 0
- job_log(j, LOG_APPLEONLY, "bootstrap_register() is deprecated. Service: %s", servicename);
-#endif
+ if (!(flags & BOOTSTRAP_PER_PID_SERVICE) && !j->legacy_LS_job) {
+ job_log(j, LOG_SCOLDING, "Performance: bootstrap_register() is deprecated. Service: %s", servicename);
+ }
job_log(j, LOG_DEBUG, "%sMach service registration attempt: %s", flags & BOOTSTRAP_PER_PID_SERVICE ? "Per PID " : "", servicename);
* 92) is a rogue application (not our UID, not root and not a child of
* us). We'll have to reconcile this design friction at a later date.
*/
- if (j->anonymous && job_get_bs(j)->parentmgr == NULL && ldc.uid != 0 && ldc.uid != getuid() && ldc.uid != 92) {
- if (getpid() == 1) {
+ if (unlikely(j->anonymous && j->mgr->parentmgr == NULL && ldc->uid != 0 && ldc->uid != getuid() && ldc->uid != 92)) {
+ if (pid1_magic) {
return VPROC_ERR_TRY_PER_USER;
} else {
return BOOTSTRAP_NOT_PRIVILEGED;
}
#endif
- ms = jobmgr_lookup_service(j->mgr, servicename, false, flags & BOOTSTRAP_PER_PID_SERVICE ? ldc.pid : 0);
+ ms = jobmgr_lookup_service(j->mgr, servicename, false, flags & BOOTSTRAP_PER_PID_SERVICE ? ldc->pid : 0);
- if (ms) {
+ if (unlikely(ms)) {
if (machservice_job(ms) != j) {
return BOOTSTRAP_NOT_PRIVILEGED;
}
job_log(j, LOG_DEBUG, "Mach service registration failed. Already active: %s", servicename);
return BOOTSTRAP_SERVICE_ACTIVE;
}
+ if (ms->recv && (serviceport != MACH_PORT_NULL)) {
+ job_log(j, LOG_ERR, "bootstrap_register() erroneously called instead of bootstrap_check_in(). Mach service: %s", servicename);
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
job_checkin(j);
machservice_delete(j, ms, false);
}
- if (serviceport != MACH_PORT_NULL) {
- if ((ms = machservice_new(j, servicename, &serviceport, flags & BOOTSTRAP_PER_PID_SERVICE ? true : false))) {
+ if (likely(serviceport != MACH_PORT_NULL)) {
+ if (likely(ms = machservice_new(j, servicename, &serviceport, flags & BOOTSTRAP_PER_PID_SERVICE ? true : false))) {
machservice_request_notifications(ms);
} else {
return BOOTSTRAP_NO_MEMORY;
}
}
+
return BOOTSTRAP_SUCCESS;
}
kern_return_t
-job_mig_look_up2(job_t j, name_t servicename, mach_port_t *serviceportp, mach_msg_type_name_t *ptype, 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, uint64_t flags)
{
struct machservice *ms;
- struct ldcred ldc;
+ struct ldcred *ldc = runtime_get_caller_creds();
kern_return_t kr;
+ bool per_pid_lookup = flags & BOOTSTRAP_PER_PID_SERVICE;
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
- runtime_get_caller_creds(&ldc);
-
/* 5641783 for the embedded hack */
#if !TARGET_OS_EMBEDDED
- if (getpid() == 1 && j->anonymous && job_get_bs(j)->parentmgr == NULL && ldc.uid != 0 && ldc.euid != 0) {
+ if (unlikely(pid1_magic && j->anonymous && j->mgr->parentmgr == NULL && ldc->uid != 0 && ldc->euid != 0)) {
return VPROC_ERR_TRY_PER_USER;
}
#endif
- if (!mspolicy_check(j, servicename, flags & BOOTSTRAP_PER_PID_SERVICE)) {
- job_log(j, LOG_NOTICE, "Policy denied Mach service lookup: %s", servicename);
+#if HAVE_SANDBOX
+ if (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
- if (flags & BOOTSTRAP_PER_PID_SERVICE) {
+ 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 (ms && machservice_hidden(ms) && !machservice_active(ms)) {
- ms = NULL;
- } else if (ms && ms->per_user_hack) {
- ms = NULL;
+ if (likely(ms)) {
+ if (machservice_hidden(ms) && !machservice_active(ms)) {
+ ms = NULL;
+ } else if (unlikely(ms->per_user_hack)) {
+ ms = NULL;
+ }
}
- if (ms) {
- launchd_assumes(machservice_port(ms) != MACH_PORT_NULL);
- job_log(j, LOG_DEBUG, "%sMach service lookup: %s", flags & BOOTSTRAP_PER_PID_SERVICE ? "Per PID " : "", servicename);
-#if 0
- /* After Leopard ships, we should enable this */
- if (j->lastlookup == ms && j->lastlookup_gennum == ms->gen_num && !j->per_user) {
- ms->bad_perf_cnt++;
- job_log(j, LOG_APPLEONLY, "Performance opportunity: Number of bootstrap_lookup(... \"%s\" ...) calls that should have been cached: %llu",
- servicename, ms->bad_perf_cnt);
+ if (likely(ms)) {
+ 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)) {
+ /* we need to think more about the per_pid_lookup logic before logging about repeated lookups */
+ job_log(j, LOG_DEBUG, "Performance: Please fix the framework that talks to \"%s\" to cache the Mach port for service: %s", ms->job->label, servicename);
}
+
j->lastlookup = ms;
j->lastlookup_gennum = ms->gen_num;
-#endif
+
*serviceportp = machservice_port(ms);
- *ptype = MACH_MSG_TYPE_COPY_SEND;
+
kr = BOOTSTRAP_SUCCESS;
- } else if (!(flags & BOOTSTRAP_PER_PID_SERVICE) && (inherited_bootstrap_port != MACH_PORT_NULL)) {
+ } else if (!per_pid_lookup && (inherited_bootstrap_port != MACH_PORT_NULL)) {
job_log(j, LOG_DEBUG, "Mach service lookup forwarded: %s", servicename);
- *ptype = MACH_MSG_TYPE_MOVE_SEND;
- kr = bootstrap_look_up(inherited_bootstrap_port, servicename, serviceportp);
- } else if (getpid() == 1 && j->anonymous && ldc.euid >= 500 && strcasecmp(job_get_bs(j)->name, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
+ /* 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);
+ /* 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) {
/*
* 5240036 Should start background session when a lookup of CCacheServer occurs
*
*/
return VPROC_ERR_TRY_PER_USER;
} else {
- job_log(j, LOG_DEBUG, "%sMach service lookup failed: %s", flags & BOOTSTRAP_PER_PID_SERVICE ? "Per PID " : "", servicename);
+ job_log(j, LOG_DEBUG, "%sMach service lookup failed: %s", per_pid_lookup ? "Per PID " : "", servicename);
kr = BOOTSTRAP_UNKNOWN_SERVICE;
}
}
kern_return_t
-job_mig_parent(job_t j, mach_port_t *parentport, mach_msg_type_name_t *pptype)
+job_mig_parent(job_t j, mach_port_t srp, mach_port_t *parentport)
{
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
job_log(j, LOG_DEBUG, "Requested parent bootstrap port");
jobmgr_t jm = j->mgr;
- *pptype = MACH_MSG_TYPE_MAKE_SEND;
-
if (jobmgr_parent(jm)) {
*parentport = jobmgr_parent(jm)->jm_port;
} else if (MACH_PORT_NULL == inherited_bootstrap_port) {
*parentport = jm->jm_port;
} else {
- *pptype = MACH_MSG_TYPE_COPY_SEND;
- *parentport = inherited_bootstrap_port;
+ 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;
}
return BOOTSTRAP_SUCCESS;
}
kern_return_t
-job_mig_info(job_t j, name_array_t *servicenamesp, unsigned int *servicenames_cnt,
- bootstrap_status_array_t *serviceactivesp, unsigned int *serviceactives_cnt)
+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;
bootstrap_status_array_t service_actives = NULL;
unsigned int cnt = 0, cnt2 = 0;
- struct machservice *ms;
jobmgr_t jm;
- job_t ji;
-
-#if TARGET_OS_EMBEDDED
- return BOOTSTRAP_NOT_PRIVILEGED;
-#endif
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
- jm = j->mgr;
+ if( g_flat_mach_namespace ) {
+ if( (j->mgr->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) || (flags & BOOTSTRAP_FORCE_LOCAL) ) {
+ jm = j->mgr;
+ } else {
+ jm = root_jobmgr;
+ }
+ } else {
+ jm = j->mgr;
+ }
- LIST_FOREACH(ji, &jm->jobs, sle) {
- SLIST_FOREACH(ms, &ji->machservices, sle) {
- if (!ms->per_pid) {
- cnt++;
- }
+ 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 ) {
+ cnt += !msi->per_pid ? 1 : 0;
}
}
}
mig_allocate((vm_address_t *)&service_names, cnt * sizeof(service_names[0]));
- if (!launchd_assumes(service_names != NULL)) {
+ if (!job_assumes(j, service_names != NULL)) {
+ goto out_bad;
+ }
+
+ mig_allocate((vm_address_t *)&service_jobs, cnt * sizeof(service_jobs[0]));
+ if (!job_assumes(j, service_jobs != NULL)) {
goto out_bad;
}
mig_allocate((vm_address_t *)&service_actives, cnt * sizeof(service_actives[0]));
- if (!launchd_assumes(service_actives != NULL)) {
+ if (!job_assumes(j, service_actives != NULL)) {
goto out_bad;
}
- LIST_FOREACH(ji, &jm->jobs, sle) {
- SLIST_FOREACH(ms, &ji->machservices, sle) {
- if (!ms->per_pid) {
- strlcpy(service_names[cnt2], machservice_name(ms), sizeof(service_names[0]));
- service_actives[cnt2] = machservice_status(ms);
+ 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_jobs[cnt2], msi->job->label, sizeof(service_jobs[0]));
+ service_actives[cnt2] = machservice_status(msi);
cnt2++;
}
}
}
- launchd_assumes(cnt == cnt2);
+ job_assumes(j, cnt == cnt2);
out:
*servicenamesp = service_names;
+ *servicejobsp = service_jobs;
*serviceactivesp = service_actives;
- *servicenames_cnt = *serviceactives_cnt = cnt;
+ *servicenames_cnt = *servicejobs_cnt = *serviceactives_cnt = cnt;
return BOOTSTRAP_SUCCESS;
if (service_names) {
mig_deallocate((vm_address_t)service_names, cnt * sizeof(service_names[0]));
}
+ if (service_jobs) {
+ mig_deallocate((vm_address_t)service_jobs, cnt * sizeof(service_jobs[0]));
+ }
if (service_actives) {
mig_deallocate((vm_address_t)service_actives, cnt * sizeof(service_actives[0]));
}
return BOOTSTRAP_NO_MEMORY;
}
-void
-job_reparent_hack(job_t j, const char *where)
+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)
{
- jobmgr_t jmi, jmi2;
+ kern_return_t kr = BOOTSTRAP_NO_MEMORY;
+ if( !launchd_assumes(j != NULL) ) {
+ return BOOTSTRAP_NO_MEMORY;
+ }
+
+ struct ldcred *ldc = runtime_get_caller_creds();
+
+ /* Only allow root processes to look up children, even if we're in the per-user launchd.
+ * Otherwise, this could be used to cross sessions, which counts as a security vulnerability
+ * in a non-flat namespace.
+ */
+ if( ldc->euid != 0 ) {
+ job_log(j, LOG_WARNING, "Attempt to look up children of bootstrap by unprivileged job.");
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+
+ unsigned int cnt = 0;
+
+ jobmgr_t jmr = j->mgr;
+ jobmgr_t jmi = NULL;
+ SLIST_FOREACH( jmi, &jmr->submgrs, sle ) {
+ cnt++;
+ }
+
+ /* Find our per-user launchds if we're PID 1. */
+ job_t ji = NULL;
+ if( pid1_magic ) {
+ LIST_FOREACH( ji, &jmr->jobs, sle ) {
+ cnt += ji->per_user ? 1 : 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]));
+ 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]));
+ 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]));
+ if( !job_assumes(j, _child_properties != NULL) ) {
+ 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) ) {
+ _child_ports[cnt2] = jmi->jm_port;
+ } else {
+ _child_ports[cnt2] = MACH_PORT_NULL;
+ }
+
+ strlcpy(_child_names[cnt2], jmi->name, sizeof(_child_names[0]));
+ _child_properties[cnt2] = jmi->properties;
+
+ 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) ) {
+ mach_port_t port = machservice_port(SLIST_FIRST(&ji->machservices));
+
+ if( job_assumes(ji, launchd_mport_copy_send(port) == KERN_SUCCESS) ) {
+ _child_ports[cnt2] = port;
+ } else {
+ _child_ports[cnt2] = MACH_PORT_NULL;
+ }
+ } else {
+ _child_ports[cnt2] = MACH_PORT_NULL;
+ }
+
+ strlcpy(_child_names[cnt2], ji->label, sizeof(_child_names[0]));
+ _child_properties[cnt2] |= BOOTSTRAP_PROPERTY_PERUSER;
+
+ cnt2++;
+ }
+ }
+
+ *child_names_cnt = cnt;
+ *child_ports_cnt = cnt;
+ *child_properties_cnt = cnt;
+
+ *child_names = _child_names;
+ *child_ports = _child_ports;
+ *child_properties = _child_properties;
+
+ unsigned int i = 0;
+ 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:
+ if( _child_ports ) {
+ mig_deallocate((vm_address_t)_child_ports, cnt * sizeof(_child_ports[0]));
+ }
+
+ if( _child_names ) {
+ mig_deallocate((vm_address_t)_child_names, cnt * sizeof(_child_ports[0]));
+ }
+
+ if( _child_properties ) {
+ mig_deallocate((vm_address_t)_child_properties, cnt * sizeof(_child_properties[0]));
+ }
+
+ return kr;
+}
+
+kern_return_t
+job_mig_transaction_count_for_pid(job_t j, pid_t p, int32_t *cnt, boolean_t *condemned)
+{
+ kern_return_t kr = KERN_FAILURE;
+ struct ldcred *ldc = runtime_get_caller_creds();
+ 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);
+ 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;
+ } else {
+ *cnt = 0;
+ *condemned = false;
+ }
+
+ kr = BOOTSTRAP_SUCCESS;
+ } else {
+ kr = BOOTSTRAP_NO_MEMORY;
+ }
+ } else {
+ kr = BOOTSTRAP_UNKNOWN_SERVICE;
+ }
+
+ return kr;
+}
+
+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();
+ if( (ldc->euid != geteuid()) && (ldc->euid != 0) ) {
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+
+ /* This is so loginwindow doesn't try to quit GUI apps that have been launched
+ * 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 ) {
+ *managed = true;
+ }
+
+ return BOOTSTRAP_SUCCESS;
+}
+
+kern_return_t
+job_mig_port_for_label(job_t j __attribute__((unused)), name_t label, mach_port_t *mp)
+{
+ struct ldcred *ldc = runtime_get_caller_creds();
+ kern_return_t kr = BOOTSTRAP_NOT_PRIVILEGED;
+
+ 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);
+ }
+
+ _mp = target_j->j_port;
+ kr = _mp != MACH_PORT_NULL ? BOOTSTRAP_SUCCESS : BOOTSTRAP_NO_MEMORY;
+ } else {
+ kr = BOOTSTRAP_NO_MEMORY;
+ }
+ }
+
+ *mp = _mp;
+ return kr;
+}
- ensure_root_bkgd_setup();
+#if !TARGET_OS_EMBEDDED
+kern_return_t
+job_mig_set_security_session(job_t j, uuid_t uuid, mach_port_t session)
+{
+ 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_t ji = NULL, jt = NULL;
+ LIST_FOREACH_SAFE( ji, &s_needing_sessions, sle, jt ) {
+ uuid_string_t uuid_str2;
+ uuid_unparse(ji->expected_audit_uuid, uuid_str2);
+
+ if( uuid_compare(uuid, ji->expected_audit_uuid) == 0 ) {
+ 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);
+ } else {
+ job_log(ji, LOG_DEBUG, "No session to set for job. Using our session.");
+ }
+
+ ji->audit_session = session;
+ LIST_REMOVE(ji, needing_session_sle);
+ job_dispatch(ji, false);
+ }
+ }
+
+ /* Each job that the session port was set for holds a reference. At the end of
+ * the loop, there will be one extra reference belonging to this MiG protocol.
+ * 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);
+
+ return KERN_SUCCESS;
+}
+#else
+kern_return_t
+job_mig_set_security_session(job_t j __attribute__((unused)), uuid_t uuid __attribute__((unused)), mach_port_t session __attribute__((unused)))
+{
+ return KERN_SUCCESS;
+}
+#endif
+
+jobmgr_t
+jobmgr_find_by_name(jobmgr_t jm, const char *where)
+{
+ jobmgr_t jmi, jmi2;
/* NULL is only passed for our custom API for LaunchServices. If that is the case, we do magic. */
if (where == NULL) {
- if (strcasecmp(j->mgr->name, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
+ if (strcasecmp(jm->name, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
where = VPROCMGR_SESSION_LOGINWINDOW;
} else {
where = VPROCMGR_SESSION_AQUA;
}
}
- if (strcasecmp(j->mgr->name, where) == 0) {
- return;
+ if (strcasecmp(jm->name, where) == 0) {
+ return jm;
+ }
+
+ if( strcasecmp(where, VPROCMGR_SESSION_BACKGROUND) == 0 && !pid1_magic ) {
+ jmi = root_jobmgr;
+ goto jm_found;
}
- SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {
- if (jmi->shutting_down) {
+ SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {
+ if (unlikely(jmi->shutting_down)) {
continue;
} else if (strcasecmp(jmi->name, where) == 0) {
goto jm_found;
- } else if (strcasecmp(jmi->name, VPROCMGR_SESSION_BACKGROUND) == 0 && getpid() == 1) {
+ } else if (strcasecmp(jmi->name, VPROCMGR_SESSION_BACKGROUND) == 0 && pid1_magic) {
SLIST_FOREACH(jmi2, &jmi->submgrs, sle) {
if (strcasecmp(jmi2->name, where) == 0) {
jmi = jmi2;
}
}
}
-
+
jm_found:
- if (job_assumes(j, jmi != NULL)) {
- struct machservice *msi;
-
- SLIST_FOREACH(msi, &j->machservices, sle) {
- LIST_REMOVE(msi, name_hash_sle);
- }
-
- LIST_REMOVE(j, sle);
- LIST_INSERT_HEAD(&jmi->jobs, j, sle);
- j->mgr = jmi;
-
- SLIST_FOREACH(msi, &j->machservices, sle) {
- LIST_INSERT_HEAD(&j->mgr->ms_hash[hash_ms(msi->name)], msi, name_hash_sle);
- }
- }
+ return jmi;
}
kern_return_t
-job_mig_move_subset(job_t j, mach_port_t target_subset, name_t session_type)
+job_mig_move_subset(job_t j, mach_port_t target_subset, name_t session_type, mach_port_t audit_session, uint64_t flags)
{
mach_msg_type_number_t l2l_i, l2l_port_cnt = 0;
mach_port_array_t l2l_ports = NULL;
mach_port_t reqport, rcvright;
kern_return_t kr = 1;
launch_data_t out_obj_array = NULL;
- struct ldcred ldc;
+ struct ldcred *ldc = runtime_get_caller_creds();
jobmgr_t jmr = NULL;
-#if TARGET_OS_EMBEDDED
- return BOOTSTRAP_NOT_PRIVILEGED;
-#endif
-
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
- runtime_get_caller_creds(&ldc);
-
- if (target_subset == MACH_PORT_NULL) {
- job_t j2;
-
- if (j->mgr->session_initialized) {
- if (ldc.uid == 0 && getpid() == 1) {
- if (strcmp(j->mgr->name, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
- job_t ji, jn;
-
- LIST_FOREACH_SAFE(ji, &j->mgr->jobs, sle, jn) {
- if (!ji->anonymous) {
- job_remove(ji);
- }
- }
-
- ensure_root_bkgd_setup();
-
- SLIST_REMOVE(&j->mgr->parentmgr->submgrs, j->mgr, jobmgr_s, sle);
- j->mgr->parentmgr = background_jobmgr;
- SLIST_INSERT_HEAD(&j->mgr->parentmgr->submgrs, j->mgr, sle);
-
- /*
- * We really should wait for all the jobs to die before proceeding. See 5351245 for more info.
- *
- * We have hacked around this in job_find() by ignoring jobs that are pending removal.
- */
-
- } else if (strcmp(j->mgr->name, VPROCMGR_SESSION_AQUA) == 0) {
- job_log(j, LOG_DEBUG, "Tried to move the Aqua session.");
- return 0;
- } else if (strcmp(j->mgr->name, VPROCMGR_SESSION_BACKGROUND) == 0) {
- job_log(j, LOG_DEBUG, "Tried to move the background session.");
- return 0;
- } else {
- job_log(j, LOG_ERR, "Tried to initialize an already setup session!");
- kr = BOOTSTRAP_NOT_PRIVILEGED;
- goto out;
- }
- } else {
- job_log(j, LOG_ERR, "Tried to initialize an already setup session!");
- kr = BOOTSTRAP_NOT_PRIVILEGED;
- goto out;
- }
- } else if (ldc.uid == 0 && getpid() == 1 && strcmp(session_type, VPROCMGR_SESSION_STANDARDIO) == 0) {
- ensure_root_bkgd_setup();
-
- SLIST_REMOVE(&j->mgr->parentmgr->submgrs, j->mgr, jobmgr_s, sle);
- j->mgr->parentmgr = background_jobmgr;
- SLIST_INSERT_HEAD(&j->mgr->parentmgr->submgrs, j->mgr, sle);
- } else if (strcmp(session_type, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
- jobmgr_t jmi;
-
- /*
- * 5330262
- *
- * We're working around LoginWindow and the WindowServer.
- *
- * In practice, there is only one LoginWindow session. Unfortunately, for certain
- * scenarios, the WindowServer spawns loginwindow, and in those cases, it frequently
- * spawns a replacement loginwindow session before cleaning up the previous one.
- *
- * We're going to use the creation of a new LoginWindow context as a clue that the
- * previous LoginWindow context is on the way out and therefore we should just
- * kick-start the shutdown of it.
- */
-
- SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {
- if (jmi->shutting_down) {
- continue;
- } else if (strcasecmp(jmi->name, session_type) == 0) {
- jobmgr_shutdown(jmi);
- break;
- }
- }
- }
-
- jobmgr_log(j->mgr, LOG_DEBUG, "Renaming to: %s", session_type);
- strcpy(j->mgr->name_init, session_type);
-
- if (job_assumes(j, (j2 = jobmgr_init_session(j->mgr, session_type, false)))) {
- job_assumes(j, job_dispatch(j2, true));
- }
-
- kr = 0;
- goto out;
- } else if (job_mig_intran2(root_jobmgr, target_subset, ldc.pid)) {
+ if (job_mig_intran2(root_jobmgr, target_subset, ldc->pid)) {
job_log(j, LOG_ERR, "Moving a session to ourself is bogus.");
kr = BOOTSTRAP_NOT_PRIVILEGED;
job_log(j, LOG_DEBUG, "Move subset attempt: 0x%x", target_subset);
- errno = kr = _vproc_grab_subset(target_subset, &reqport, &rcvright, &out_obj_array, &l2l_ports, &l2l_port_cnt);
+ kr = _vproc_grab_subset(target_subset, &reqport, &rcvright, &out_obj_array, &l2l_ports, &l2l_port_cnt);
if (!job_assumes(j, kr == 0)) {
goto out;
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)) != NULL)) {
+ if (!job_assumes(j, (jmr = jobmgr_new(j->mgr, reqport, rcvright, false, session_type, false, audit_session)) != NULL)) {
kr = BOOTSTRAP_NO_MEMORY;
goto out;
}
+ jmr->properties |= BOOTSTRAP_PROPERTY_MOVEDSUBSET;
+
+ /* This is a hack. We should be doing this in jobmgr_new(), but since we're in the middle of
+ * 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 ) {
+ /* This is so awful. */
+ /* Remove the job from its current job manager. */
+ LIST_REMOVE(j, sle);
+ LIST_REMOVE(j, pid_hash_sle);
+
+ /* Put the job into the target job manager. */
+ LIST_INSERT_HEAD(&jmr->jobs, j, sle);
+ LIST_INSERT_HEAD(&jmr->active_jobs[ACTIVE_JOB_HASH(j->p)], j, pid_hash_sle);
+
+ j->mgr = jmr;
+ job_set_global_on_demand(j, true);
+ }
+
for (l2l_i = 0; l2l_i < l2l_port_cnt; l2l_i++) {
launch_data_t tmp, obj_at_idx;
struct machservice *ms;
j_for_service = jobmgr_find_by_pid(jmr, target_pid, true);
- if (!j_for_service) {
+ if (unlikely(!j_for_service)) {
/* The PID probably exited */
job_assumes(j, launchd_mport_deallocate(l2l_ports[l2l_i]) == KERN_SUCCESS);
continue;
}
- if ((ms = machservice_new(j_for_service, serv_name, &l2l_ports[l2l_i], serv_perpid))) {
+ if (likely(ms = machservice_new(j_for_service, serv_name, &l2l_ports[l2l_i], serv_perpid))) {
+ job_log(j, LOG_DEBUG, "Importing %s into new bootstrap.", serv_name);
machservice_request_notifications(ms);
}
}
return kr;
}
+kern_return_t
+job_mig_init_session(job_t j, name_t session_type, mach_port_t audit_session)
+{
+ job_t j2;
+
+ kern_return_t kr = BOOTSTRAP_NO_MEMORY;
+ if (j->mgr->session_initialized) {
+ job_log(j, LOG_ERR, "Tried to initialize an already setup session!");
+ kr = BOOTSTRAP_NOT_PRIVILEGED;
+ } else if (strcmp(session_type, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
+ jobmgr_t jmi;
+
+ /*
+ * 5330262
+ *
+ * We're working around LoginWindow and the WindowServer.
+ *
+ * In practice, there is only one LoginWindow session. Unfortunately, for certain
+ * scenarios, the WindowServer spawns loginwindow, and in those cases, it frequently
+ * spawns a replacement loginwindow session before cleaning up the previous one.
+ *
+ * We're going to use the creation of a new LoginWindow context as a clue that the
+ * previous LoginWindow context is on the way out and therefore we should just
+ * kick-start the shutdown of it.
+ */
+
+ SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {
+ if (unlikely(jmi->shutting_down)) {
+ continue;
+ } else if (strcasecmp(jmi->name, session_type) == 0) {
+ jobmgr_shutdown(jmi);
+ break;
+ }
+ }
+ }
+
+ jobmgr_log(j->mgr, LOG_DEBUG, "Initializing as %s", session_type);
+ 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));
+ kr = BOOTSTRAP_SUCCESS;
+ }
+
+ return kr;
+}
+
+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_log(j, LOG_DEBUG, "Job wants to move to %s session.", session_name);
+
+ 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;
+ }
+
+ 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);
+ 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;
+ }
+
+ 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 {
+ target_jm->properties |= BOOTSTRAP_PROPERTY_IMPLICITSUBSET;
+ }
+ }
+
+ if( !job_assumes(j, target_jm != NULL) ) {
+ job_log(j, LOG_WARNING, "Could not find %s session!", session_name);
+ return BOOTSTRAP_NO_MEMORY;
+ }
+
+ /* Remove the job from it's current job manager. */
+ LIST_REMOVE(j, sle);
+ 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_REMOVE(ji, global_env_sle);
+ break;
+ }
+ }
+
+ /* Put the job into the target job manager. */
+ 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 ) {
+ 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) ) {
+ struct machservice *msi = NULL, *msit = NULL;
+ 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);
+ }
+ }
+
+ j->mgr = target_jm;
+ j->migratory = true;
+ *new_bsport = target_jm->jm_port;
+
+ /* 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
+ * the StandardIO session by default. So we'll hold a reference on that job to prevent
+ * ourselves from going away.
+ */
+ runtime_add_ref();
+
+ return KERN_SUCCESS;
+}
+
kern_return_t
job_mig_take_subset(job_t j, mach_port_t *reqport, mach_port_t *rcvright,
vm_offset_t *outdata, mach_msg_type_number_t *outdataCnt,
jobmgr_t jm;
job_t ji;
-#if TARGET_OS_EMBEDDED
- return BOOTSTRAP_NOT_PRIVILEGED;
-#endif
-
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
jm = j->mgr;
- if (getpid() != 1) {
+ if (unlikely(!pid1_magic)) {
job_log(j, LOG_ERR, "Only the system launchd will transfer Mach sub-bootstraps.");
return BOOTSTRAP_NOT_PRIVILEGED;
- } else if (jobmgr_parent(jm) == NULL) {
+ }
+ if (unlikely(jobmgr_parent(jm) == NULL)) {
job_log(j, LOG_ERR, "Root Mach bootstrap cannot be transferred.");
return BOOTSTRAP_NOT_PRIVILEGED;
- } else if (strcasecmp(jm->name, VPROCMGR_SESSION_AQUA) == 0) {
+ }
+ if (unlikely(strcasecmp(jm->name, VPROCMGR_SESSION_AQUA) == 0)) {
job_log(j, LOG_ERR, "Cannot transfer a setup GUI session.");
return BOOTSTRAP_NOT_PRIVILEGED;
- } else if (!j->anonymous) {
+ }
+ if (unlikely(!j->anonymous)) {
job_log(j, LOG_ERR, "Only the anonymous job can transfer Mach sub-bootstraps.");
return BOOTSTRAP_NOT_PRIVILEGED;
}
}
mig_allocate((vm_address_t *)&ports, cnt * sizeof(ports[0]));
- if (!launchd_assumes(ports != NULL)) {
+ if (!job_assumes(j, ports != NULL)) {
goto out_bad;
}
}
}
- launchd_assumes(cnt == cnt2);
+ job_assumes(j, cnt == cnt2);
+ runtime_ktrace0(RTKT_LAUNCHD_DATA_PACK);
packed_size = launch_data_pack(outdata_obj_array, (void *)*outdata, *outdataCnt, NULL, NULL);
if (!job_assumes(j, packed_size != 0)) {
goto out_bad;
}
/* Since we use recursion, we need an artificial depth for subsets */
- if (bsdepth > 100) {
+ if (unlikely(bsdepth > 100)) {
job_log(j, LOG_ERR, "Mach sub-bootstrap create request failed. Depth greater than: %d", bsdepth);
return BOOTSTRAP_NO_MEMORY;
}
- if ((jmr = jobmgr_new(j->mgr, requestorport, MACH_PORT_NULL, false, NULL)) == NULL) {
- if (requestorport == MACH_PORT_NULL) {
+ 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 (unlikely(requestorport == MACH_PORT_NULL)) {
return BOOTSTRAP_NOT_PRIVILEGED;
}
return BOOTSTRAP_NO_MEMORY;
}
*subsetportp = jmr->jm_port;
+ jmr->properties |= BOOTSTRAP_PROPERTY_EXPLICITSUBSET;
+
+ job_log(j, LOG_DEBUG, "Job created a subset named \"%s\"", jmr->name);
return BOOTSTRAP_SUCCESS;
}
-kern_return_t
-job_mig_create_service(job_t j, name_t servicename, mach_port_t *serviceportp)
-{
- struct machservice *ms;
-
- if (!launchd_assumes(j != NULL)) {
- return BOOTSTRAP_NO_MEMORY;
- }
-
- if (job_prog(j)[0] == '\0') {
- job_log(j, LOG_ERR, "Mach service creation requires a target server: %s", servicename);
- return BOOTSTRAP_NOT_PRIVILEGED;
- }
-
- if (!j->legacy_mach_job) {
- job_log(j, LOG_ERR, "bootstrap_create_service() is only allowed against legacy Mach jobs: %s", servicename);
- return BOOTSTRAP_NOT_PRIVILEGED;
- }
-
- ms = jobmgr_lookup_service(j->mgr, servicename, false, 0);
- if (ms) {
- job_log(j, LOG_DEBUG, "Mach service creation attempt for failed. Already exists: %s", servicename);
- return BOOTSTRAP_NAME_IN_USE;
- }
-
- job_checkin(j);
-
- *serviceportp = MACH_PORT_NULL;
- ms = machservice_new(j, servicename, serviceportp, false);
-
- if (!launchd_assumes(ms != NULL)) {
- goto out_bad;
- }
-
- return BOOTSTRAP_SUCCESS;
-
-out_bad:
- launchd_assumes(launchd_mport_close_recv(*serviceportp) == KERN_SUCCESS);
- return BOOTSTRAP_NO_MEMORY;
-}
-
kern_return_t
job_mig_embedded_wait(job_t j, name_t targetlabel, integer_t *waitstatus)
{
}
kern_return_t
-job_mig_embedded_kickstart(job_t j, name_t targetlabel, pid_t *out_pid, mach_port_t *out_name_port)
+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)
{
- struct ldcred ldc;
- kern_return_t kr;
+ struct ldcred *ldc = runtime_get_caller_creds();
job_t otherj;
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_UNKNOWN_SERVICE;
}
- runtime_get_caller_creds(&ldc);
-
- if (ldc.euid != 0 && ldc.euid != geteuid()
#if TARGET_OS_EMBEDDED
- && j->username && otherj->username
- && strcmp(j->username, otherj->username) != 0
+ 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( 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;
}
- kr = task_name_for_pid(mach_task_self(), otherj->p, out_name_port);
+ /* 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.
+ */
+
+ kern_return_t kr = task_name_for_pid(mach_task_self(), otherj->p, out_name_port);
if (!job_assumes(j, kr == 0)) {
return kr;
}
+ if (!job_setup_machport(otherj)) {
+ return BOOTSTRAP_NO_MEMORY;
+ }
+
+ *obsrvr_port = otherj->j_port;
*out_pid = otherj->p;
return 0;
kern_return_t
job_mig_wait(job_t j, mach_port_t srp, integer_t *waitstatus)
{
+#if 0
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
-#if 0
- struct ldcred ldc;
- runtime_get_caller_creds(&ldc);
-#endif
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);
+ }
+ struct ldcred *ldc = runtime_get_caller_creds();
+ job_t calling_j = job_mig_intran2(j->mgr, MACH_PORT_NULL, ldc->pid);
+
+ return job_mig_wait2(calling_j, j, srp, waitstatus, true);
+#endif
}
kern_return_t
-job_mig_uncork_fork(job_t j)
+job_mig_wait2(job_t j, job_t target_j, mach_port_t srp, integer_t *status, boolean_t legacy)
{
- if (!launchd_assumes(j != NULL)) {
+ if( !launchd_assumes(j != NULL) ) {
return BOOTSTRAP_NO_MEMORY;
}
-
- if (!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( !launchd_assumes(target_j != NULL) ) {
+ return BOOTSTRAP_NO_MEMORY;
}
-
- job_uncork_fork(j);
- j->stall_before_exec = false;
- return 0;
-}
-
-kern_return_t
-job_mig_set_service_policy(job_t j, pid_t target_pid, uint64_t flags, name_t target_service)
-{
- struct ldcred ldc;
- job_t target_j;
-
- if (!launchd_assumes(j != NULL)) {
+ if( !launchd_assumes(status != NULL) ) {
return BOOTSTRAP_NO_MEMORY;
}
-
- runtime_get_caller_creds(&ldc);
-
-#if TARGET_OS_EMBEDDED
- if( ldc.euid ) {
- return BOOTSTRAP_NOT_PRIVILEGED;
+
+ if( target_j->p == 0 ) {
+ *status = target_j->last_exit_status;
+ return BOOTSTRAP_SUCCESS;
}
-#else
- if( ldc.euid && (ldc.euid != getuid()) ) {
- int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, target_pid };
- struct kinfo_proc kp;
- size_t len = sizeof(kp);
-
- job_assumes(j, sysctl(mib, 4, &kp, &len, NULL, 0) != -1);
- job_assumes(j, len == sizeof(kp));
-
- uid_t kp_euid = kp.kp_eproc.e_ucred.cr_uid;
- uid_t kp_uid = kp.kp_eproc.e_pcred.p_ruid;
-
- if( ldc.euid == kp_euid ) {
- job_log(j, LOG_DEBUG, "Working around rdar://problem/5982485 and allowing job to set policy for PID %u.", target_pid);
- } else {
- job_log(j, LOG_ERR, "Denied Mach service policy update requested by UID/EUID %u/%u against PID %u with UID/EUID %u/%u due to mismatched credentials.", ldc.uid, ldc.euid, target_pid, kp_uid, kp_euid);
-
- return BOOTSTRAP_NOT_PRIVILEGED;
- }
+
+ if( !job_assumes(j, waiting4exit_new(target_j, srp, legacy) == true) ) {
+ return BOOTSTRAP_NO_MEMORY;
}
-#endif
+
+ return MIG_NO_REPLY;
+}
- if (!job_assumes(j, (target_j = jobmgr_find_by_pid(j->mgr, target_pid, true)) != NULL)) {
+kern_return_t
+job_mig_uncork_fork(job_t j)
+{
+ if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
- if (SLIST_EMPTY(&j->mspolicies)) {
- job_log(j, LOG_DEBUG, "Setting policy on job \"%s\" for Mach service: %s", target_j->label, target_service);
- if (target_service[0]) {
- job_assumes(j, mspolicy_new(target_j, target_service, flags & BOOTSTRAP_ALLOW_LOOKUP, flags & BOOTSTRAP_PER_PID_SERVICE, false));
- } else {
- target_j->deny_unknown_mslookups = !(flags & BOOTSTRAP_ALLOW_LOOKUP);
- target_j->deny_job_creation = (bool)(flags & BOOTSTRAP_DENY_JOB_CREATION);
- }
- } else {
- job_log(j, LOG_WARNING, "Jobs that have policies assigned to them may not set policies.");
- return BOOTSTRAP_NOT_PRIVILEGED;
+ 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;
}
+ job_uncork_fork(j);
+ j->stall_before_exec = false;
return 0;
}
kern_return_t
-job_mig_spawn(job_t j, vm_offset_t indata, mach_msg_type_number_t indataCnt, pid_t *child_pid, mach_port_t *obsvr_port)
+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)
{
launch_data_t input_obj = NULL;
size_t data_offset = 0;
- struct ldcred ldc;
+ struct ldcred *ldc = runtime_get_caller_creds();
job_t jr;
-#if TARGET_OS_EMBEDDED
- return BOOTSTRAP_NOT_PRIVILEGED;
-#endif
-
- runtime_get_caller_creds(&ldc);
-
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
return BOOTSTRAP_NOT_PRIVILEGED;
}
- if (getpid() == 1 && ldc.euid && ldc.uid) {
+#if HAVE_SANDBOX
+ if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
+ 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;
}
return 1;
}
+ runtime_ktrace0(RTKT_LAUNCHD_DATA_UNPACK);
if (!job_assumes(j, (input_obj = launch_data_unpack((void *)indata, indataCnt, NULL, 0, &data_offset, NULL)) != NULL)) {
return 1;
}
- jr = jobmgr_import2(j->mgr, input_obj);
+ 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__);
+ return 1;
+ }
+
+ jr = jobmgr_import2(target_jm ?: j->mgr, input_obj);
if (!job_assumes(j, jr != NULL)) {
switch (errno) {
}
}
- job_reparent_hack(jr, NULL);
-
- if (getpid() == 1) {
- jr->mach_uid = ldc.uid;
+ if (pid1_magic) {
+ jr->mach_uid = ldc->uid;
}
- jr->unload_at_exit = true;
- jr->wait4pipe_eof = true;
+ jr->legacy_LS_job = true;
jr->abandon_pg = true;
jr->stall_before_exec = jr->wait4debugger;
jr->wait4debugger = false;
+ jr->audit_session = audit_session;
+ uuid_clear(jr->expected_audit_uuid);
jr = job_dispatch(jr, true);
void
jobmgr_init(bool sflag)
{
- const char *root_session_type = getpid() == 1 ? VPROCMGR_SESSION_SYSTEM : VPROCMGR_SESSION_BACKGROUND;
-
- launchd_assert((root_jobmgr = jobmgr_new(NULL, MACH_PORT_NULL, MACH_PORT_NULL, sflag, root_session_type)) != NULL);
+ const char *root_session_type = pid1_magic ? VPROCMGR_SESSION_SYSTEM : VPROCMGR_SESSION_BACKGROUND;
+ SLIST_INIT(&s_curious_jobs);
+ 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);
+
+ 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);
+ }
+ }
+ s_no_hang_fd = _fd(s_no_hang_fd);
}
size_t
}
bool
-mspolicy_copy(job_t j_to, job_t j_from)
-{
- struct mspolicy *msp;
-
- SLIST_FOREACH(msp, &j_from->mspolicies, sle) {
- if (!mspolicy_new(j_to, msp->name, msp->allow, msp->per_pid, true)) {
- return false;
- }
- }
-
- return true;
-}
-
-bool
-mspolicy_new(job_t j, const char *name, bool allow, bool pid_local, bool skip_check)
+waiting4removal_new(job_t j, mach_port_t rp)
{
- struct mspolicy *msp;
-
- if (!skip_check) SLIST_FOREACH(msp, &j->mspolicies, sle) {
- if (msp->per_pid != pid_local) {
- continue;
- } else if (strcmp(msp->name, name) == 0) {
- return false;
- }
- }
+ struct waiting_for_removal *w4r;
- if ((msp = calloc(1, sizeof(struct mspolicy) + strlen(name) + 1)) == NULL) {
+ if (!job_assumes(j, (w4r = malloc(sizeof(struct waiting_for_removal))) != NULL)) {
return false;
}
- strcpy((char *)msp->name, name);
- msp->per_pid = pid_local;
- msp->allow = allow;
+ w4r->reply_port = rp;
- SLIST_INSERT_HEAD(&j->mspolicies, msp, sle);
+ SLIST_INSERT_HEAD(&j->removal_watchers, w4r, sle);
return true;
}
void
-mspolicy_setup(launch_data_t obj, const char *key, void *context)
-{
- job_t j = context;
-
- if (launch_data_get_type(obj) != LAUNCH_DATA_BOOL) {
- job_log(j, LOG_WARNING, "Invalid object type for Mach service policy key: %s", key);
- return;
- }
-
- job_assumes(j, mspolicy_new(j, key, launch_data_get_bool(obj), false, false));
-}
-
-bool
-mspolicy_check(job_t j, const char *name, bool pid_local)
+waiting4removal_delete(job_t j, struct waiting_for_removal *w4r)
{
- struct mspolicy *mspi;
-
- SLIST_FOREACH(mspi, &j->mspolicies, sle) {
- if (mspi->per_pid != pid_local) {
- continue;
- } else if (strcmp(mspi->name, name) != 0) {
- continue;
- }
- return mspi->allow;
- }
-
- return !j->deny_unknown_mslookups;
-}
+ job_assumes(j, job_mig_send_signal_reply(w4r->reply_port, 0) == 0);
-void
-mspolicy_delete(job_t j, struct mspolicy *msp)
-{
- SLIST_REMOVE(&j->mspolicies, msp, mspolicy, sle);
+ SLIST_REMOVE(&j->removal_watchers, w4r, waiting_for_removal, sle);
- free(msp);
+ free(w4r);
}
-bool
-waiting4removal_new(job_t j, mach_port_t rp)
+bool
+waiting4exit_new(job_t j, mach_port_t rp, bool legacy)
{
- struct waiting_for_removal *w4r;
-
- if (!job_assumes(j, (w4r = malloc(sizeof(struct waiting_for_removal))) != NULL)) {
+ struct waiting_for_exit *w4e = NULL;
+ if( !job_assumes(j, (w4e = malloc(sizeof(struct waiting_for_exit))) != NULL) ) {
return false;
}
-
- w4r->reply_port = rp;
-
- SLIST_INSERT_HEAD(&j->removal_watchers, w4r, sle);
-
+
+ w4e->rp = rp;
+ w4e->legacy = legacy;
+ LIST_INSERT_HEAD(&j->exit_watchers, w4e, sle);
+
return true;
}
void
-waiting4removal_delete(job_t j, struct waiting_for_removal *w4r)
+waiting4exit_delete(job_t j, struct waiting_for_exit *w4e)
{
- 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);
+ 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
int mib[] = { CTL_KERN, KERN_MAXPROC };
int max = 100;
size_t max_sz = sizeof(max);
-
+
launchd_assumes(sysctl(mib, 2, &max, &max_sz, NULL, 0) != -1);
-
+
return max;
}
+/* See rdar://problem/6271234 */
void
-do_file_init(void)
+eliminate_double_reboot(void)
{
+ if( unlikely(!pid1_magic) ) {
+ return;
+ }
+
struct stat sb;
+ const char *argv[] = { _PATH_BSHELL, "/etc/rc.deferred_install", NULL };
+ char *try_again = "Will try again at next boot.";
+ int result = ~0;
+
+ 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_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( !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;
+ }
+
+ 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);
+ }
+ } else {
+ jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Confirmed that deferred install script exited, but couldn't confirm that it was successful. %s", try_again);
+ }
+ }
+out:
+ 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( !jobmgr_assumes(root_jobmgr, unlink(argv[1]) != -1) ) {
+ 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);
+ }
+}
+
+static void
+jetsam_priority_from_job(job_t j, bool front, jetsam_priority_entry_t *jp)
+{
+ jp->pid = j->p;
+ jp->flags |= front ? kJetsamFlagsFrontmost : 0;
+}
- launchd_assert(mach_timebase_info(&tbi) == 0);
+static int
+job_cmp(const job_t *lhs, const job_t *rhs)
+{
+ job_t _lhs = *lhs;
+ job_t _rhs = *rhs;
+ /* Sort in descending order. (Priority correlates to the soonishness with which you will be killed.) */
+ if( _lhs->jetsam_priority > _rhs->jetsam_priority ) {
+ return -1;
+ } else if( _lhs->jetsam_priority < _rhs->jetsam_priority ) {
+ return 1;
+ }
+
+ return 0;
+}
- if (stat("/AppleInternal", &sb) == 0) {
- do_apple_internal_magic = true;
+int
+launchd_set_jetsam_priorities(launch_data_t priorities)
+{
+ if( !launchd_assumes(launch_data_get_type(priorities) == LAUNCH_DATA_ARRAY) ) {
+ return EINVAL;
+ }
+
+ jobmgr_t jm = NULL;
+#if !TARGET_OS_EMBEDDED
+ /* For testing. */
+ jm = jobmgr_find_by_name(root_jobmgr, VPROCMGR_SESSION_AQUA);
+ 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;
+
+ if( !g_embedded_privileged_action ) {
+ return EPERM;
}
+#endif
+
+ size_t npris = launch_data_array_get_count(priorities);
+
+ job_t ji = NULL;
+ size_t i = 0;
+ for( i = 0; i < npris; i++ ) {
+ launch_data_t ldi = launch_data_array_get_index(priorities, i);
+ if( !launchd_assumes(launch_data_get_type(ldi) == LAUNCH_DATA_DICTIONARY) ) {
+ continue;
+ }
+
+ launch_data_t label = NULL;
+ if( !launchd_assumes(label = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMLABEL)) ) {
+ continue;
+ }
+ const char *_label = launch_data_get_string(label);
+
+ ji = job_find(_label);
+ if( !launchd_assumes(ji != NULL) ) {
+ continue;
+ }
+
+ launch_data_t pri;
+ long long _pri = 0;
+ if( !launchd_assumes(pri = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMPRIORITY)) ) {
+ continue;
+ }
+ _pri = launch_data_get_integer(pri);
+
+ if( ji->jetsam_priority == LAUNCHD_JETSAM_PRIORITY_UNSET ) {
+ LIST_INSERT_HEAD(&ji->mgr->jetsam_jobs, ji, jetsam_sle);
+ ji->mgr->jetsam_jobs_cnt++;
+ }
+ ji->jetsam_priority = _pri;
+
+ launch_data_t frontmost = NULL;
+ if( !(frontmost = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMFRONTMOST)) ) {
+ ji->jetsam_frontmost = false;
+ continue;
+ }
+ ji->jetsam_frontmost = launch_data_get_bool(frontmost);
+ }
+
+ i = 0;
+ job_t *jobs = (job_t *)calloc(jm->jetsam_jobs_cnt, sizeof(job_t));
+ LIST_FOREACH( ji, &jm->jetsam_jobs, jetsam_sle ) {
+ if( ji->p ) {
+ jobs[i] = ji;
+ i++;
+ }
+ }
+ size_t totalpris = i;
+
+ int result = EINVAL;
+ if( launchd_assumes(totalpris > 0) ) {
+ qsort((void *)jobs, totalpris, sizeof(job_t), (int (*)(const void *, const void *))job_cmp);
+
+ jetsam_priority_entry_t *jpris = (jetsam_priority_entry_t *)calloc(totalpris, sizeof(jetsam_priority_entry_t));
+ if( !launchd_assumes(jpris != NULL) ) {
+ result = ENOMEM;
+ } else {
+ for( i = 0; i < totalpris; i++ ) {
+ jetsam_priority_from_job(jobs[i], jobs[i]->jetsam_frontmost, &jpris[i]);
+ }
+
+ int _result = 0;
+ 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);
+ }
+ }
+ free(jobs);
+
+ return result;
}
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
+#include "launchd_runtime.h"
#include "bootstrap.h"
#include "launch.h"
extern jobmgr_t root_jobmgr;
extern mach_port_t inherited_bootstrap_port;
+extern mach_port_t g_audit_session_port;
+extern au_asid_t g_audit_session;
+extern bool g_flat_mach_namespace;
+extern bool g_embedded_privileged_action;
void jobmgr_init(bool);
jobmgr_t jobmgr_shutdown(jobmgr_t jm);
void jobmgr_dispatch_all_semaphores(jobmgr_t jm);
+void jobmgr_dispatch_all_interested(jobmgr_t jm, job_t j);
jobmgr_t jobmgr_delete_anything_with_port(jobmgr_t jm, mach_port_t port);
launch_data_t job_export_all(void);
void job_stop(job_t j);
void job_checkin(job_t j);
void job_remove(job_t j);
+bool job_is_god(job_t j);
job_t job_import(launch_data_t pload);
launch_data_t job_import_bulk(launch_data_t pload);
job_t job_mig_intran(mach_port_t mp);
void job_mig_destructor(job_t j);
void job_ack_no_senders(job_t j);
void job_log(job_t j, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4)));
+void job_set_pid_crashed(pid_t p);
+
+int launchd_set_jetsam_priorities(launch_data_t priorities);
#endif
serverprefix x_;
routine handle_kqueue(
- __port : mach_port_t;
- __fd : integer_t);
-
-routine handle_mport(
- __port : mach_port_t);
+ __port : mach_port_t;
+ __fd : integer_t);
--- /dev/null
+#include "launchd_ktrace.h"
+
+void
+runtime_ktrace1(runtime_ktrace_code_t code)
+{
+ void *ra = __builtin_extract_return_addr(__builtin_return_address(1));
+
+ /* This syscall returns EINVAL when the trace isn't enabled. */
+ if (do_apple_internal_logging) {
+ syscall(180, code, 0, 0, 0, (long)ra);
+ }
+}
+
+void
+runtime_ktrace0(runtime_ktrace_code_t code)
+{
+ void *ra = __builtin_extract_return_addr(__builtin_return_address(0));
+
+ /* This syscall returns EINVAL when the trace isn't enabled. */
+ if (do_apple_internal_logging) {
+ syscall(180, code, 0, 0, 0, (long)ra);
+ }
+}
+
+void
+runtime_ktrace(runtime_ktrace_code_t code, long a, long b, long c)
+{
+ void *ra = __builtin_extract_return_addr(__builtin_return_address(0));
+
+ /* This syscall returns EINVAL when the trace isn't enabled. */
+ if (do_apple_internal_logging) {
+ syscall(180, code, a, b, c, (long)ra);
+ }
+}
--- /dev/null
+#ifndef __LAUNCHD_KTRACE_H__
+#define __LAUNCHD_KTRACE_H__
+
+#include <unistd.h>
+#include <stdbool.h>
+
+extern bool do_apple_internal_logging;
+
+#ifndef DBG_LAUNCHD
+ #define DBG_LAUNCHD 34
+#endif
+
+/* Class(8) | SubClass(8) | Code(14) | Qual(2) */
+#define RTKT_CODE(c) ((DBG_LAUNCHD << 24) | (((c) & 0x3fffff) << 2))
+
+typedef enum {
+ RTKT_LAUNCHD_STARTING = RTKT_CODE(1),
+ RTKT_LAUNCHD_EXITING = RTKT_CODE(2),
+ RTKT_LAUNCHD_FINDING_STRAY_PG = RTKT_CODE(3),
+ RTKT_LAUNCHD_FINDING_ALL_STRAYS = RTKT_CODE(4),
+ RTKT_LAUNCHD_FINDING_EXECLESS = RTKT_CODE(5),
+ RTKT_LAUNCHD_FINDING_WEIRD_UIDS = RTKT_CODE(6),
+ RTKT_LAUNCHD_DATA_PACK = RTKT_CODE(7),
+ RTKT_LAUNCHD_DATA_UNPACK = RTKT_CODE(8),
+ RTKT_LAUNCHD_BUG = RTKT_CODE(9),
+ RTKT_LAUNCHD_MACH_IPC = RTKT_CODE(10),
+ RTKT_LAUNCHD_BSD_KEVENT = RTKT_CODE(11),
+ RTKT_VPROC_TRANSACTION_INCREMENT = RTKT_CODE(12),
+ RTKT_VPROC_TRANSACTION_DECREMENT = RTKT_CODE(13),
+} runtime_ktrace_code_t;
+
+/* All of these log the return address as "arg4" */
+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);
+
+#endif /* __LAUNCHD_KTRACE_H__ */
* Copyright, 1990. All rights reserved.
*/
-type pid_t = integer_t;
-type pid_array_t = ^array [] of pid_t;
-type uid_t = integer_t;
-type gid_t = integer_t;
-type vproc_gsk_t = integer_t;
-type logmsg_t = c_string[*:2048];
-type cmd_t = c_string[512];
-type name_t = c_string[128];
-type name_array_t = ^array [] of name_t;
-type bootstrap_status_t = integer_t;
+type pid_t = integer_t;
+type pid_array_t = ^array [] of pid_t;
+type uid_t = natural_t;
+type gid_t = natural_t;
+type vproc_gsk_t = integer_t;
+type logmsg_t = c_string[*:2048];
+type cmd_t = c_string[512];
+type name_t = c_string[128];
+type name_array_t = ^array [] of name_t;
+type bootstrap_property_t = natural_t;
+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 job_t = mach_port_t
- intran: job_t job_mig_intran(mach_port_t)
- outtran: mach_port_t job_mig_outtran(job_t)
- destructor: job_mig_destructor(job_t)
- cusertype: vproc_mig_t;
+ intran : job_t job_mig_intran(mach_port_t)
+ outtran : mach_port_t job_mig_outtran(job_t)
+ destructor : job_mig_destructor(job_t)
+ cusertype : vproc_mig_t;
/*
- * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2008 Apple Computer, Inc. All rights reserved.
*
* @APPLE_APACHE_LICENSE_HEADER_START@
*
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
-static const char *const __rcs_file_version__ = "$Revision: 23748 $";
+static const char *const __rcs_file_version__ = "$Revision: 23929 $";
#include "config.h"
#include "launchd_runtime.h"
#include <mach/mach_interface.h>
#include <mach/host_info.h>
#include <mach/mach_host.h>
+#include <mach/mach_time.h>
#include <mach/exception.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/proc.h>
#include <sys/event.h>
#include <sys/mount.h>
#include <sys/reboot.h>
#include <sys/fcntl.h>
+#include <sys/kdebug.h>
#include <bsm/libbsm.h>
#include <malloc/malloc.h>
#include <unistd.h>
#include "launchd_internalServer.h"
#include "launchd_internal.h"
#include "notifyServer.h"
-#include "excServer.h"
+#include "mach_excServer.h"
/* We shouldn't be including these */
#include "launch.h"
#include "launchd.h"
#include "launchd_core_logic.h"
+#include "vproc.h"
+#include "vproc_priv.h"
#include "vproc_internal.h"
#include "protocol_job_reply.h"
static int bulk_kev_cnt;
static pthread_t kqueue_demand_thread;
-static pthread_t demand_thread;
-static void *mport_demand_loop(void *arg);
+static void mportset_callback(void);
+static kq_callback kqmportset_callback = (kq_callback)mportset_callback;
static void *kqueue_demand_loop(void *arg);
-static void log_kevent_struct(int level, struct kevent *kev, int indx);
-static boolean_t launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply);
+boolean_t launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply);
static void record_caller_creds(mach_msg_header_t *mh);
static void launchd_runtime2(mach_msg_size_t msg_size, mig_reply_error_t *bufRequest, mig_reply_error_t *bufReply);
static mach_msg_size_t max_msg_size;
static size_t mig_cb_table_sz;
static timeout_callback runtime_idle_callback;
static mach_msg_timeout_t runtime_idle_timeout;
-static audit_token_t *au_tok;
+static struct ldcred ldc;
static size_t runtime_busy_cnt;
+static size_t runtime_standby_cnt;
static STAILQ_HEAD(, logmsg_s) logmsg_queue = STAILQ_HEAD_INITIALIZER(logmsg_queue);
static mach_port_t drain_reply_port;
static void runtime_log_uncork_pending_drain(void);
static kern_return_t runtime_log_pack(vm_offset_t *outval, mach_msg_type_number_t *outvalCnt);
-static void runtime_log_push(void);
static bool logmsg_add(struct runtime_syslog_attr *attr, int err_num, const char *msg);
static void logmsg_remove(struct logmsg_s *lm);
+static void do_file_init(void) __attribute__((constructor));
+static mach_timebase_info_data_t tbi;
+static uint64_t tbi_safe_math_max;
+static uint64_t time_of_mach_msg_return;
+static double tbi_float_val;
static const int sigigns[] = { SIGHUP, SIGINT, SIGPIPE, SIGALRM, SIGTERM,
SIGURG, SIGTSTP, SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU, SIGIO, SIGXCPU,
SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGINFO, SIGUSR1, SIGUSR2
};
static sigset_t sigign_set;
+static FILE *ourlogfile;
+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_use_gmalloc = false;
+bool g_log_per_user_shutdown = false;
+#if !TARGET_OS_EMBEDDED
+bool g_log_pid1_shutdown = true;
+#else
+bool g_log_pid1_shutdown = false;
+#endif
+bool g_log_strict_usage = false;
+pid_t g_wsp = 0;
mach_port_t
runtime_get_kernel_port(void)
return launchd_internal_port;
}
+// static const char *__crashreporter_info__ = "";
+
+static int internal_mask_pri = LOG_UPTO(LOG_NOTICE);
+
+
void
launchd_runtime_init(void)
{
mach_msg_size_t mxmsgsz;
- pthread_attr_t attr;
+ pid_t p = getpid();
launchd_assert((mainkq = kqueue()) != -1);
launchd_assert((errno = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &demand_port_set)) == KERN_SUCCESS);
launchd_assert((errno = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &ipc_port_set)) == KERN_SUCCESS);
+ launchd_assert(kevent_mod(demand_port_set, EVFILT_MACHPORT, EV_ADD, 0, 0, &kqmportset_callback) != -1);
+
launchd_assert(launchd_mport_create_recv(&launchd_internal_port) == KERN_SUCCESS);
launchd_assert(launchd_mport_make_send(launchd_internal_port) == KERN_SUCCESS);
}
launchd_assert(runtime_add_mport(launchd_internal_port, launchd_internal_demux, mxmsgsz) == KERN_SUCCESS);
+ launchd_assert(pthread_create(&kqueue_demand_thread, NULL, kqueue_demand_loop, NULL) == 0);
+ launchd_assert(pthread_detach(kqueue_demand_thread) == 0);
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
- launchd_assert(pthread_create(&kqueue_demand_thread, &attr, kqueue_demand_loop, NULL) == 0);
- pthread_attr_destroy(&attr);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
- launchd_assert(pthread_create(&demand_thread, &attr, mport_demand_loop, NULL) == 0);
- pthread_attr_destroy(&attr);
+ launchd_assumes(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)) != -1);
}
void
}
}
-void *
-mport_demand_loop(void *arg __attribute__((unused)))
-{
- mach_msg_empty_rcv_t dummy;
- kern_return_t kr;
-
- for (;;) {
- kr = mach_msg(&dummy.header, MACH_RCV_MSG|MACH_RCV_LARGE, 0, 0, demand_port_set, 0, MACH_PORT_NULL);
- if (kr == MACH_RCV_PORT_CHANGED) {
- break;
- } else if (!launchd_assumes(kr == MACH_RCV_TOO_LARGE)) {
- continue;
- }
- launchd_assumes(handle_mport(launchd_internal_port) == 0);
- }
-
- return NULL;
-}
-
const char *
proc_flags_to_C_names(unsigned int flags)
{
const char *
reboot_flags_to_C_names(unsigned int flags)
{
-#define MAX_RB_STR "RB_ASKNAME|RB_SINGLE|RB_NOSYNC|RB_KDB|RB_HALT|RB_INITNAME|RB_DFLTROOT|RB_ALTBOOT|RB_UNIPROC|RB_SAFEBOOT|RB_UPSDELAY|0xdeadbeeffeedface"
+#define MAX_RB_STR "RB_ASKNAME|RB_SINGLE|RB_NOSYNC|RB_HALT|RB_INITNAME|RB_DFLTROOT|RB_ALTBOOT|RB_UNIPROC|RB_SAFEBOOT|RB_UPSDELAY|0xdeadbeeffeedface"
static char flags_buf[sizeof(MAX_RB_STR)];
char *flags_off = NULL;
}
void
-log_kevent_struct(int level, struct kevent *kev, int indx)
+log_kevent_struct(int level, struct kevent *kev_base, int indx)
{
+ struct kevent *kev = &kev_base[indx];
const char *filter_str;
char ident_buf[100];
char filter_buf[100];
unsigned short flags = kev->flags;
unsigned int fflags = kev->fflags;
+ if (likely(!(LOG_MASK(level) & internal_mask_pri))) {
+ return;
+ }
+
if (flags) while (flags) {
if (flags_off) {
*flags_off = '|';
else FLAGIF(EV_ONESHOT)
else FLAGIF(EV_ERROR)
else {
- flags_off += sprintf(flags_off, "0x%x", flags);
+ flags_off += sprintf(flags_off, "0x%hx", flags);
flags = 0;
}
}
}
break;
default:
- snprintf(filter_buf, sizeof(filter_buf), "%d", kev->filter);
+ snprintf(filter_buf, sizeof(filter_buf), "%hd", kev->filter);
filter_str = filter_buf;
break;
}
indx, kev->udata, kev->data, ident_buf, filter_str, flags_buf, fflags_buf);
}
-kern_return_t
-x_handle_mport(mach_port_t junk __attribute__((unused)))
+void
+mportset_callback(void)
{
mach_port_name_array_t members;
mach_msg_type_number_t membersCnt;
unsigned int i;
if (!launchd_assumes((errno = mach_port_get_set_status(mach_task_self(), demand_port_set, &members, &membersCnt)) == KERN_SUCCESS)) {
- return 1;
+ return;
}
for (i = 0; i < membersCnt; i++) {
#if 0
if (launchd_assumes(kev.udata != NULL)) {
#endif
- log_kevent_struct(LOG_DEBUG, &kev, 0);
+ log_kevent_struct(LOG_DEBUG, &kev, i);
(*((kq_callback *)kev.udata))(kev.udata, &kev);
#if 0
} else {
- log_kevent_struct(LOG_ERR, &kev);
+ log_kevent_struct(LOG_ERR, &kev, i);
}
#endif
/* the callback may have tainted our ability to continue this for loop */
launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)members,
(vm_size_t) membersCnt * sizeof(mach_port_name_t)) == KERN_SUCCESS);
-
- return 0;
}
void *
x_handle_kqueue(mach_port_t junk __attribute__((unused)), integer_t fd)
{
struct timespec ts = { 0, 0 };
- struct kevent kev[BULK_KEV_MAX];
+ struct kevent *kevi, kev[BULK_KEV_MAX];
int i;
bulk_kev = kev;
- launchd_assumes((bulk_kev_cnt = kevent(fd, NULL, 0, kev, BULK_KEV_MAX, &ts)) != -1);
-
- if (bulk_kev_cnt > 0) {
-#if 0
- Dl_info dli;
-
- if (launchd_assumes(malloc_size(kev.udata) || dladdr(kev.udata, &dli))) {
-#endif
+ if (launchd_assumes((bulk_kev_cnt = kevent(fd, NULL, 0, kev, BULK_KEV_MAX, &ts)) != -1)) {
+ #if 0
for (i = 0; i < bulk_kev_cnt; i++) {
- log_kevent_struct(LOG_DEBUG, &kev[i], i);
+ log_kevent_struct(LOG_DEBUG, kev, i);
}
+ #endif
for (i = 0; i < bulk_kev_cnt; i++) {
bulk_kev_i = i;
- if (kev[i].filter) {
- (*((kq_callback *)kev[i].udata))(kev[i].udata, &kev[i]);
+ kevi = &kev[i];
+
+ if (kevi->filter) {
+ runtime_syslog(LOG_DEBUG, "Dispatching kevent...");
+ log_kevent_struct(LOG_DEBUG, kev, i);
+ #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.
+ */
+ Dl_info dli;
+ if (launchd_assumes(malloc_size(kevi->udata) || dladdr(kevi->udata, &dli))) {
+ 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);
+ } else {
+ runtime_syslog(LOG_ERR, "The following kevent had invalid context data.");
+ log_kevent_struct(LOG_EMERG, kevi, i);
+ }
+ #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);
+ #endif
}
}
-#if 0
- } else {
- log_kevent_struct(LOG_ERR, &kev);
- }
-#endif
}
bulk_kev = NULL;
return 0;
}
-
-
void
launchd_runtime(void)
{
int flags = VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE;
for (;;) {
- if (req) {
+ if (likely(req)) {
launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)req, mz) == KERN_SUCCESS);
req = NULL;
}
- if (resp) {
+ if (likely(resp)) {
launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)resp, mz) == KERN_SUCCESS);
resp = NULL;
}
if (which == MACH_NOTIFY_NO_SENDERS) {
/* Always make sure the send count is zero, in case a receive right is reused */
errno = mach_port_set_mscount(mach_task_self(), name, 0);
- if (errno != KERN_SUCCESS) {
+ if (unlikely(errno != KERN_SUCCESS)) {
return errno;
}
}
errno = mach_port_request_notification(mach_task_self(), name, which, msgc, where,
MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous);
- if (errno == 0 && previous != MACH_PORT_NULL) {
+ if (likely(errno == 0) && previous != MACH_PORT_NULL) {
launchd_assumes(launchd_mport_deallocate(previous) == KERN_SUCCESS);
}
launchd_assumes(sigprocmask(SIG_SETMASK, &oset, NULL) != -1);
launchd_assumes(launchd_set_bport(MACH_PORT_NULL) == KERN_SUCCESS);
} else {
+ pid_t p = -getpid();
+ launchd_assumes(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)) != -1);
+
launchd_assumes(sigprocmask(SIG_SETMASK, &emptyset, NULL) != -1);
}
msg_size = round_page(msg_size + MAX_TRAILER_SIZE);
- if (needed_table_sz > mig_cb_table_sz) {
+ if (unlikely(needed_table_sz > mig_cb_table_sz)) {
needed_table_sz *= 2; /* Let's try and avoid realloc'ing for a while */
mig_callback *new_table = malloc(needed_table_sz);
return KERN_RESOURCE_SHORTAGE;
}
- if (mig_cb_table) {
+ if (likely(mig_cb_table)) {
memcpy(new_table, mig_cb_table, mig_cb_table_sz);
free(mig_cb_table);
}
return errno = mach_port_insert_right(mach_task_self(), name, name, MACH_MSG_TYPE_MAKE_SEND);
}
+kern_return_t
+launchd_mport_copy_send(mach_port_t name)
+{
+ return errno = mach_port_insert_right(mach_task_self(), name, name, MACH_MSG_TYPE_COPY_SEND);
+}
+
kern_return_t
launchd_mport_close_recv(mach_port_t name)
{
case EVFILT_READ:
case EVFILT_WRITE:
break;
+ case EVFILT_TIMER:
+ /* Workaround 5225889 */
+ if (flags & EV_ADD) {
+ kevent_mod(ident, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
+ }
+ /* fall through */
default:
flags |= EV_CLEAR;
break;
if (flags & EV_ADD && !launchd_assumes(udata != NULL)) {
errno = EINVAL;
return -1;
+ } else if( (flags & EV_DELETE) && bulk_kev ) {
+ 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 ) {
+ runtime_syslog(LOG_DEBUG, "Pruning the following kevent:");
+ log_kevent_struct(LOG_DEBUG, &bulk_kev[i], i);
+ bulk_kev[i].filter = (short)0;
+ }
+ }
}
EV_SET(&kev, ident, filter, flags, fflags, data, udata);
} else if (notify_server_routine(Request)) {
return notify_server(Request, Reply);
} else {
- return exc_server(Request, Reply);
+ return mach_exc_server(Request, Reply);
}
}
kern_return_t
-do_mach_notify_port_destroyed(mach_port_t notify __attribute__((unused)),
- mach_port_t rights)
+do_mach_notify_port_destroyed(mach_port_t notify __attribute__((unused)), mach_port_t rights)
{
/* This message is sent to us when a receive right is returned to us. */
}
kern_return_t
-do_mach_notify_port_deleted(mach_port_t notify __attribute__((unused)),
- mach_port_name_t name __attribute__((unused)))
+do_mach_notify_port_deleted(mach_port_t notify __attribute__((unused)), mach_port_name_t name __attribute__((unused)))
{
/* If we deallocate/destroy/mod_ref away a port with a pending
* notification, the original notification message is replaced with
}
kern_return_t
-do_mach_notify_no_senders(mach_port_t notify,
- mach_port_mscount_t mscount __attribute__((unused)))
+do_mach_notify_no_senders(mach_port_t notify, mach_port_mscount_t mscount __attribute__((unused)))
{
job_t j = job_mig_intran(notify);
kern_return_t
do_mach_notify_send_once(mach_port_t notify __attribute__((unused)))
{
- /* This message is sent to us every time we close a port that we have
- * outstanding Mach notification requests on. We can safely ignore this
- * message.
+ /*
+ * This message is sent for each send-once right that is deallocated
+ * without being used.
*/
return KERN_SUCCESS;
}
kern_return_t
-do_mach_notify_dead_name(mach_port_t notify __attribute__((unused)),
- mach_port_name_t name)
+do_mach_notify_dead_name(mach_port_t notify __attribute__((unused)), mach_port_name_t name)
{
/* This message is sent to us when one of our send rights no longer has
* a receiver somewhere else on the system.
trailer_size = tp->msgh_trailer_size - (mach_msg_size_t)(sizeof(mach_msg_trailer_type_t) - sizeof(mach_msg_trailer_size_t));
- if (trailer_size < (mach_msg_size_t)sizeof(audit_token_t)) {
- au_tok = NULL;
- return;
+ 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);
}
- au_tok = &tp->msgh_audit;
}
-bool
-runtime_get_caller_creds(struct ldcred *ldc)
+struct ldcred *
+runtime_get_caller_creds(void)
{
- if (!au_tok) {
- return false;
- }
-
- audit_token_to_au32(*au_tok, /* audit UID */ NULL, &ldc->euid,
- &ldc->egid, &ldc->uid, &ldc->gid, &ldc->pid,
- &ldc->asid, /* au_tid_t */ NULL);
+ return &ldc;
+}
- return true;
+mach_msg_return_t
+launchd_exc_runtime_once(mach_port_t port, mach_msg_size_t rcv_msg_size, mach_msg_size_t send_msg_size, mig_reply_error_t *bufRequest, mig_reply_error_t *bufReply, mach_msg_timeout_t to)
+{
+ mach_msg_return_t mr = ~MACH_MSG_SUCCESS;
+ mach_msg_option_t rcv_options = MACH_RCV_MSG |
+ MACH_RCV_TIMEOUT |
+ MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) |
+ MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) ;
+
+ do {
+ mr = mach_msg(&bufRequest->Head, rcv_options, 0, rcv_msg_size, port, to, MACH_PORT_NULL);
+ switch( mr ) {
+ case MACH_RCV_TIMED_OUT :
+ runtime_syslog(LOG_DEBUG, "Message queue is empty.");
+ break;
+ case MACH_RCV_TOO_LARGE :
+ runtime_syslog(LOG_INFO, "Message is larger than %u bytes.", rcv_msg_size);
+ break;
+ default :
+ launchd_assumes(mr == MACH_MSG_SUCCESS);
+ }
+
+ 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;
+ }
+
+ mach_msg_return_t smr = ~MACH_MSG_SUCCESS;
+ mach_msg_option_t send_options = MACH_SEND_MSG |
+ MACH_SEND_TIMEOUT ;
+
+ 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);
+ 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_INVALID_DEST :
+ 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) ) {
+ runtime_syslog(LOG_WARNING, "Couldn't deliver exception reply: 0x%x", smr);
+ }
+ break;
+ }
+ }
+ } while( 0 );
+
+ return mr;
}
void
mig_callback the_demux;
mach_msg_timeout_t to;
mach_msg_return_t mr;
+ size_t busy_cnt;
options = MACH_RCV_MSG|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) |
MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0);
tmp_options = options;
for (;;) {
+ busy_cnt = runtime_busy_cnt + runtime_standby_cnt;
to = MACH_MSG_TIMEOUT_NONE;
- if (msg_size != max_msg_size) {
- /* The buffer isn't big enougth to receive messages anymore... */
+ if (unlikely(msg_size != max_msg_size)) {
+ /* The buffer isn't big enough to receive messages anymore... */
tmp_options &= ~MACH_RCV_MSG;
options &= ~MACH_RCV_MSG;
if (!(tmp_options & MACH_SEND_MSG)) {
}
}
- if ((tmp_options & MACH_RCV_MSG) && (runtime_idle_callback || (runtime_busy_cnt == 0))) {
+ if ((tmp_options & MACH_RCV_MSG) && (runtime_idle_callback || (busy_cnt == 0))) {
tmp_options |= MACH_RCV_TIMEOUT;
if (!(tmp_options & MACH_SEND_TIMEOUT)) {
- to = runtime_busy_cnt ? runtime_idle_timeout : (RUNTIME_ADVISABLE_IDLE_TIMEOUT * 1000);
+ #if !TARGET_OS_EMBEDDED
+ to = busy_cnt ? runtime_idle_timeout : (_vproc_standby_timeout() * 1000);
+ #else
+ to = runtime_idle_timeout;
+ #endif
}
}
mr = mach_msg(&bufReply->Head, tmp_options, bufReply->Head.msgh_size,
msg_size, ipc_port_set, to, MACH_PORT_NULL);
+ time_of_mach_msg_return = runtime_get_opaque_time();
+
tmp_options = options;
- if (mr == MACH_SEND_INVALID_DEST || mr == MACH_SEND_TIMED_OUT) {
+ /* It looks like the compiler doesn't optimize switch(unlikely(...)) See: 5691066 */
+ if (unlikely(mr)) switch (mr) {
+ case MACH_SEND_INVALID_DEST:
+ case MACH_SEND_TIMED_OUT:
/* We need to clean up and start over. */
if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
mach_msg_destroy(&bufReply->Head);
}
continue;
- } else if (mr == MACH_RCV_TIMED_OUT) {
+ case MACH_RCV_TIMED_OUT:
if (to != MACH_MSG_TIMEOUT_NONE) {
- if (runtime_busy_cnt == 0) {
+ if (busy_cnt == 0) {
+ runtime_syslog(LOG_INFO, "Idle exiting.");
launchd_shutdown();
} else if (runtime_idle_callback) {
runtime_idle_callback();
}
}
continue;
- } else if (!launchd_assumes(mr == MACH_MSG_SUCCESS)) {
+ default:
+ if( !launchd_assumes(mr == MACH_MSG_SUCCESS) ) {
+ runtime_syslog(LOG_ERR, "mach_msg(): %u: %s", mr, mach_error_string(mr));
+ }
continue;
}
bufRequest = bufReply;
bufReply = bufTemp;
- if (!(tmp_options & MACH_RCV_MSG)) {
+ if (unlikely(!(tmp_options & MACH_RCV_MSG))) {
continue;
}
/* we have another request message */
-
+#if 0
if (!launchd_assumes(mig_cb_table != NULL)) {
break;
}
+#endif
the_demux = mig_cb_table[MACH_PORT_INDEX(bufRequest->Head.msgh_local_port)];
+#if 0
if (!launchd_assumes(the_demux != NULL)) {
break;
}
+#endif
record_caller_creds(&bufRequest->Head);
-
- /*
- * This is a total hack. We really need a bit in the kernel's proc
- * struct to declare our intent.
- */
- static int no_hang_fd = -1;
- if (no_hang_fd == -1) {
- no_hang_fd = _fd(open("/dev/autofs_nowait", 0));
- }
+ runtime_ktrace(RTKT_LAUNCHD_MACH_IPC|DBG_FUNC_START, bufRequest->Head.msgh_local_port, bufRequest->Head.msgh_id, (long)the_demux);
if (the_demux(&bufRequest->Head, &bufReply->Head) == FALSE) {
/* XXX - also gross */
- if (bufRequest->Head.msgh_id == MACH_NOTIFY_NO_SENDERS) {
+ if (likely(bufRequest->Head.msgh_id == MACH_NOTIFY_NO_SENDERS)) {
notify_server(&bufRequest->Head, &bufReply->Head);
}
}
+ runtime_ktrace(RTKT_LAUNCHD_MACH_IPC|DBG_FUNC_END, bufReply->Head.msgh_remote_port, bufReply->Head.msgh_bits, bufReply->RetCode);
+
+ /* bufReply is a union. If MACH_MSGH_BITS_COMPLEX is set, then bufReply->RetCode is assumed to be zero. */
if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
- if (bufReply->RetCode == MIG_NO_REPLY) {
- bufReply->Head.msgh_remote_port = MACH_PORT_NULL;
- } else if ((bufReply->RetCode != KERN_SUCCESS) && (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
- /* destroy the request - but not the reply port */
- bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
- mach_msg_destroy(&bufRequest->Head);
+ if (unlikely(bufReply->RetCode != KERN_SUCCESS)) {
+ if (likely(bufReply->RetCode == MIG_NO_REPLY)) {
+ bufReply->Head.msgh_remote_port = MACH_PORT_NULL;
+ } else if (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
+ /* destroy the request - but not the reply port */
+ bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
+ mach_msg_destroy(&bufRequest->Head);
+ }
}
}
- if (bufReply->Head.msgh_remote_port != MACH_PORT_NULL) {
+ if (likely(bufReply->Head.msgh_remote_port != MACH_PORT_NULL)) {
tmp_options |= MACH_SEND_MSG;
- if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE) {
+ if (unlikely(MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE)) {
tmp_options |= MACH_SEND_TIMEOUT;
}
}
case EVFILT_VNODE:
case EVFILT_WRITE:
case EVFILT_READ:
- if ((int)bulk_kev[i].ident == fd) {
+ if (unlikely((int)bulk_kev[i].ident == fd)) {
runtime_syslog(LOG_DEBUG, "Skipping kevent index: %d", i);
bulk_kev[i].filter = 0;
}
return close(fd);
}
-static FILE *ourlogfile;
-
void
runtime_closelog(void)
{
+ runtime_log_push();
+
if (ourlogfile) {
launchd_assumes(fflush(ourlogfile) == 0);
launchd_assumes(runtime_fsync(fileno(ourlogfile)) != -1);
int
runtime_fsync(int fd)
{
- if (debug_shutdown_hangs) {
+#if 0
+ if (do_apple_internal_logging) {
return fcntl(fd, F_FULLFSYNC, NULL);
} else {
return fsync(fd);
}
+#else
+ return fsync(fd);
+#endif
}
-static int internal_mask_pri = LOG_UPTO(LOG_NOTICE);
-//static int internal_mask_pri = LOG_UPTO(LOG_DEBUG);
-
int
runtime_setlogmask(int maskpri)
{
runtime_syslog(int pri, const char *message, ...)
{
struct runtime_syslog_attr attr = {
- "com.apple.launchd", "com.apple.launchd",
- getpid() == 1 ? "System" : "Background",
- pri, getuid(), getpid(), getpid()
+ g_my_label,
+ g_my_label,
+ pid1_magic ? "System" : "Background",
+ pri,
+ getuid(),
+ getpid(),
+ getpid()
};
va_list ap;
va_start(ap, message);
-
runtime_vsyslog(&attr, message, ap);
va_end(ap);
void
runtime_vsyslog(struct runtime_syslog_attr *attr, const char *message, va_list args)
{
- static pthread_mutex_t ourlock = PTHREAD_MUTEX_INITIALIZER;
- static struct timeval shutdown_start;
- static struct timeval prev_msg;
- static int apple_internal_logging = 1;
- struct timeval tvnow, tvd_total, tvd_msg_delta = { 0, 0 };
- struct stat sb;
int saved_errno = errno;
char newmsg[10000];
- size_t i, j;
-
- if (!(LOG_MASK(attr->priority) & internal_mask_pri)) {
- goto out;
- }
+ bool echo_to_console= false;
- if (apple_internal_logging == 1) {
- apple_internal_logging = stat("/AppleInternal", &sb);
- }
-
-
- if (!(debug_shutdown_hangs && getpid() == 1)) {
- if (attr->priority == LOG_APPLEONLY) {
- if (apple_internal_logging == -1) {
- goto out;
- }
+ if (attr->priority == LOG_APPLEONLY) {
+ if (do_apple_internal_logging) {
attr->priority = LOG_NOTICE;
+ } else {
+ return;
}
- vsnprintf(newmsg, sizeof(newmsg), message, args);
- logmsg_add(attr, saved_errno, newmsg);
- goto out;
- }
-
- if (shutdown_start.tv_sec == 0) {
- gettimeofday(&shutdown_start, NULL);
+ } else if( attr->priority == LOG_SCOLDING ) {
+ attr->priority = g_log_strict_usage ? LOG_NOTICE : LOG_DEBUG;
}
- if (gettimeofday(&tvnow, NULL) == -1) {
- tvnow.tv_sec = 0;
- tvnow.tv_usec = 0;
+ if( attr->priority & LOG_CONSOLE ) {
+ echo_to_console = true;
+ attr->priority &= ~LOG_CONSOLE;
}
- pthread_mutex_lock(&ourlock);
-
- if (ourlogfile == NULL) {
- rename("/var/log/launchd-shutdown.log", "/var/log/launchd-shutdown.log.1");
- ourlogfile = fopen("/var/log/launchd-shutdown.log", "a");
- }
-
- pthread_mutex_unlock(&ourlock);
-
- if (ourlogfile == NULL) {
- goto out;
- }
-
- if (message == NULL) {
- goto out;
- }
-
- timersub(&tvnow, &shutdown_start, &tvd_total);
-
- if (prev_msg.tv_sec != 0) {
- timersub(&tvnow, &prev_msg, &tvd_msg_delta);
+ if (!(LOG_MASK(attr->priority) & internal_mask_pri)) {
+ return;
}
- prev_msg = tvnow;
+ vsnprintf(newmsg, sizeof(newmsg), message, args);
- snprintf(newmsg, sizeof(newmsg), "%3ld.%06d%4ld.%06d%6u %-40s%6u %-40s ",
- tvd_total.tv_sec, tvd_total.tv_usec,
- tvd_msg_delta.tv_sec, tvd_msg_delta.tv_usec,
- attr->from_pid, attr->from_name,
- attr->about_pid, attr->about_name);
-
- for (i = 0, j = strlen(newmsg); message[i];) {
- if (message[i] == '%' && message[i + 1] == 'm') {
- char *errs = strerror(saved_errno);
- strcpy(newmsg + j, errs ? errs : "unknown error");
- j += strlen(newmsg + j);
- i += 2;
- } else {
- newmsg[j] = message[i];
- j++;
- i++;
- }
+ 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);
}
- strcpy(newmsg + j, "\n");
-
- vfprintf(ourlogfile, newmsg, args);
-
-out:
- runtime_log_uncork_pending_drain();
+ logmsg_add(attr, saved_errno, newmsg);
}
bool
/* we do this to make the unpacking for the log_drain cause unalignment faults */
lm_sz = ROUND_TO_64BIT_WORD_SIZE(lm_sz);
- if (!(lm = calloc(1, lm_sz))) {
+ if (unlikely((lm = calloc(1, lm_sz)) == NULL)) {
return false;
}
data_off = lm->data;
- launchd_assumes(gettimeofday(&lm->when, NULL) != -1);
+ lm->when = runtime_get_wall_time();
lm->from_pid = attr->from_pid;
lm->about_pid = attr->about_pid;
lm->err_num = err_num;
mig_allocate(outval, *outvalCnt);
- if (*outval == 0) {
+ if (unlikely(*outval == 0)) {
return 1;
}
offset = (void *)*outval;
+ 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 logfile1[NAME_MAX];
+ snprintf(logfile1, sizeof(logfile1), "/var/tmp/launchd-%s.shutdown.log.1", g_username);
+
+ rename(logfile, logfile1);
+ ourlogfile = fopen(logfile, "a");
+ }
+
+ static int64_t shutdown_start = 0;
+ if( shutdown_start == 0 ) {
+ shutdown_start = runtime_get_wall_time();
+ }
+
while ((lm = STAILQ_FIRST(&logmsg_queue))) {
- lm->from_name -= (size_t)lm;
- lm->about_name -= (size_t)lm;
- lm->msg -= (size_t)lm;
- lm->session_name -= (size_t)lm;
+ int64_t log_delta = lm->when - shutdown_start;
+ 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);
+ }
+
+ lm->from_name_offset = lm->from_name - (char *)lm;
+ lm->about_name_offset = lm->about_name - (char *)lm;
+ lm->msg_offset = lm->msg - (char *)lm;
+ lm->session_name_offset = lm->session_name - (char *)lm;
memcpy(offset, lm, lm->obj_sz);
logmsg_remove(lm);
}
+
+ if( ourlogfile ) {
+ fflush(ourlogfile);
+ }
return 0;
}
tmp_port = drain_reply_port;
drain_reply_port = MACH_PORT_NULL;
- if ((errno = job_mig_log_drain_reply(tmp_port, 0, outval, outvalCnt))) {
+ 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
runtime_log_push(void)
{
+ static pthread_mutex_t ourlock = PTHREAD_MUTEX_INITIALIZER;
+ static int64_t shutdown_start, log_delta;
mach_msg_type_number_t outvalCnt;
+ struct logmsg_s *lm;
vm_offset_t outval;
if (logmsg_queue_cnt == 0) {
launchd_assumes(STAILQ_EMPTY(&logmsg_queue));
return;
- } else if (getpid() == 1) {
+ } else if (!pid1_magic) {
+ if (runtime_log_pack(&outval, &outvalCnt) == 0) {
+ launchd_assumes(_vprocmgr_log_forward(inherited_bootstrap_port, (void *)outval, outvalCnt) == NULL);
+ mig_deallocate(outval, outvalCnt);
+ }
return;
}
- if (runtime_log_pack(&outval, &outvalCnt) != 0) {
+ if (likely(!shutdown_in_progress && !fake_shutdown_in_progress)) {
+ runtime_log_uncork_pending_drain();
return;
}
- launchd_assumes(_vprocmgr_log_forward(inherited_bootstrap_port, (void *)outval, outvalCnt) == NULL);
+ if (unlikely(shutdown_start == 0)) {
+ shutdown_start = runtime_get_wall_time();
+ launchd_log_vm_stats();
+ }
- mig_deallocate(outval, outvalCnt);
+ pthread_mutex_lock(&ourlock);
+
+ 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");
+ }
+
+ pthread_mutex_unlock(&ourlock);
+
+ if (unlikely(!ourlogfile)) {
+ return;
+ }
+
+ while ((lm = STAILQ_FIRST(&logmsg_queue))) {
+ log_delta = lm->when - shutdown_start;
+
+ 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);
+
+ logmsg_remove(lm);
+ }
+
+ fflush(ourlogfile);
}
kern_return_t
}
for (lm_walk = (struct logmsg_s *)inval; (data_left > 0) && (lm_walk->obj_sz <= data_left); lm_walk = ((void *)lm_walk + lm_walk->obj_sz)) {
+ /* malloc() does not return NULL if you ask it for an allocation of size 0.
+ * It will return a valid pointer that can be passed to free(). If we don't
+ * do this check, we'll wind up corrupting our heap in the subsequent
+ * assignments.
+ *
+ * We break out if this check fails because, obj_sz is supposed to include
+ * the size of the logmsg_s struct. If it claims to be of zero size, we
+ * 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) ) {
+ runtime_syslog(LOG_WARNING, "Encountered a log message of size 0 with %u bytes left in forwarded data. Ignoring remaining messages.", data_left);
+ break;
+ }
+
+ /* If malloc() keeps failing, we shouldn't put additional pressure on the system
+ * by attempting to add more messages to the log until it returns success
+ * log a failure, hope pressure lets off, and move on.
+ */
if (!launchd_assumes(lm = malloc(lm_walk->obj_sz))) {
- continue;
+ runtime_syslog(LOG_WARNING, "Failed to allocate %llu bytes for log message with %u bytes left in forwarded data. Ignoring remaining messages.", lm_walk->obj_sz, data_left);
+ break;
}
memcpy(lm, lm_walk, lm_walk->obj_sz);
kern_return_t
runtime_log_drain(mach_port_t srp, vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
{
- if (logmsg_queue_cnt == 0) {
- launchd_assumes(STAILQ_EMPTY(&logmsg_queue));
- launchd_assumes(drain_reply_port == 0);
+ launchd_assumes(drain_reply_port == 0);
+ 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
runtime_add_ref(void)
{
+ if (!pid1_magic) {
+ #if !TARGET_OS_EMBEDDED
+ _vproc_transaction_begin();
+ #endif
+ }
runtime_busy_cnt++;
}
void
runtime_del_ref(void)
{
+ if (!pid1_magic) {
+ #if !TARGET_OS_EMBEDDED
+ if( _vproc_transaction_count() == 0 ) {
+ runtime_syslog(LOG_INFO, "Exiting cleanly.");
+ }
+
+ runtime_closelog();
+ _vproc_transaction_end();
+ #endif
+ }
runtime_busy_cnt--;
}
+void
+runtime_add_weak_ref(void)
+{
+ if (!pid1_magic) {
+ #if !TARGET_OS_EMBEDDED
+ _vproc_standby_begin();
+ #endif
+ }
+ runtime_standby_cnt++;
+}
+
+void
+runtime_del_weak_ref(void)
+{
+ if (!pid1_magic) {
+ #if !TARGET_OS_EMBEDDED
+ _vproc_standby_end();
+ #endif
+ }
+ runtime_standby_cnt--;
+}
+
kern_return_t
-catch_exception_raise(mach_port_t exception_port __attribute__((unused)),
- mach_port_t thread, mach_port_t task,
- exception_type_t exception, exception_data_t code,
- mach_msg_type_number_t codeCnt)
+catch_mach_exception_raise(mach_port_t exception_port __attribute__((unused)), mach_port_t thread, mach_port_t task,
+ exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt)
{
- runtime_syslog(LOG_NOTICE, "%s(): thread: 0x%x task: 0x%x type: 0x%x code: %p codeCnt: 0x%x",
- __func__, thread, task, exception, code, codeCnt);
+ pid_t p4t = -1;
+ 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);
+
launchd_assumes(launchd_mport_deallocate(thread) == KERN_SUCCESS);
launchd_assumes(launchd_mport_deallocate(task) == KERN_SUCCESS);
- return 0;
+ return KERN_SUCCESS;
}
kern_return_t
-catch_exception_raise_state(mach_port_t exception_port __attribute__((unused)),
- exception_type_t exception,
- const exception_data_t code, mach_msg_type_number_t codeCnt,
- int *flavor,
- const thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
- thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
+catch_mach_exception_raise_state(mach_port_t exception_port __attribute__((unused)),
+ exception_type_t exception, const mach_exception_data_t code, mach_msg_type_number_t codeCnt,
+ int *flavor, const thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
{
runtime_syslog(LOG_NOTICE, "%s(): type: 0x%x code: %p codeCnt: 0x%x flavor: %p old_state: %p old_stateCnt: 0x%x new_state: %p new_stateCnt: %p",
__func__, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
-
+
memcpy(new_state, old_state, old_stateCnt * sizeof(old_state[0]));
*new_stateCnt = old_stateCnt;
- return 0;
+ return KERN_SUCCESS;
}
kern_return_t
-catch_exception_raise_state_identity(mach_port_t exception_port __attribute__((unused)),
- mach_port_t thread, mach_port_t task,
- exception_type_t exception,
- exception_data_t code, mach_msg_type_number_t codeCnt,
- int *flavor,
- thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
- thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
+catch_mach_exception_raise_state_identity(mach_port_t exception_port __attribute__((unused)), mach_port_t thread, mach_port_t task,
+ exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt,
+ int *flavor, thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
{
- runtime_syslog(LOG_NOTICE, "%s(): thread: 0x%x task: 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__, thread, task, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
+ pid_t p4t = -1;
+
+ 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);
+
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);
- return 0;
+ return KERN_SUCCESS;
+}
+
+void
+launchd_log_vm_stats(void)
+{
+ static struct vm_statistics orig_stats;
+ static bool did_first_pass;
+ unsigned int count = HOST_VM_INFO_COUNT;
+ struct vm_statistics stats, *statsp;
+ mach_port_t mhs = mach_host_self();
+
+ statsp = did_first_pass ? &stats : &orig_stats;
+
+ if (!launchd_assumes(host_statistics(mhs, HOST_VM_INFO, (host_info_t)statsp, &count) == KERN_SUCCESS)) {
+ return;
+ }
+
+ 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",
+ stats.free_count - orig_stats.free_count,
+ stats.active_count - orig_stats.active_count,
+ stats.inactive_count - orig_stats.inactive_count,
+ stats.reactivations - orig_stats.reactivations,
+ stats.pageins - orig_stats.pageins,
+ stats.pageouts - orig_stats.pageouts,
+ stats.faults - orig_stats.faults,
+ stats.cow_faults - orig_stats.cow_faults,
+ stats.purgeable_count - orig_stats.purgeable_count,
+ stats.purges - orig_stats.purges);
+ } else {
+ runtime_syslog(LOG_DEBUG, "VM statistics (now): Free: %d Active: %d Inactive: %d Reactivations: %d PageIns: %d PageOuts: %d Faults: %d COW-Faults: %d Purgeable: %d Purges: %d",
+ orig_stats.free_count,
+ orig_stats.active_count,
+ orig_stats.inactive_count,
+ orig_stats.reactivations,
+ orig_stats.pageins,
+ orig_stats.pageouts,
+ orig_stats.faults,
+ orig_stats.cow_faults,
+ orig_stats.purgeable_count,
+ orig_stats.purges);
+
+ did_first_pass = true;
+ }
+
+ launchd_mport_deallocate(mhs);
+}
+
+int64_t
+runtime_get_wall_time(void)
+{
+ struct timeval tv;
+ int64_t r;
+
+ launchd_assumes(gettimeofday(&tv, NULL) != -1);
+
+ r = tv.tv_sec;
+ r *= USEC_PER_SEC;
+ r += tv.tv_usec;
+
+ return r;
+}
+
+uint64_t
+runtime_get_opaque_time(void)
+{
+ return mach_absolute_time();
+}
+
+uint64_t
+runtime_get_opaque_time_of_event(void)
+{
+ return time_of_mach_msg_return;
+}
+
+uint64_t
+runtime_get_nanoseconds_since(uint64_t o)
+{
+ return runtime_opaque_time_to_nano(runtime_get_opaque_time_of_event() - o);
+}
+
+uint64_t
+runtime_opaque_time_to_nano(uint64_t o)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ if (unlikely(tbi.numer != tbi.denom)) {
+#elif defined(__ppc__) || defined(__ppc64__)
+ if (likely(tbi.numer != tbi.denom)) {
+#else
+ if (tbi.numer != tbi.denom) {
+#endif
+#ifdef __LP64__
+ __uint128_t tmp = o;
+ tmp *= tbi.numer;
+ tmp /= tbi.denom;
+ o = tmp;
+#else
+ if (o <= tbi_safe_math_max) {
+ o *= tbi.numer;
+ o /= tbi.denom;
+ } else {
+ double d = o;
+ d *= tbi_float_val;
+ o = d;
+ }
+#endif
+ }
+
+ return o;
+}
+
+void
+do_file_init(void)
+{
+ struct stat sb;
+
+ launchd_assert(mach_timebase_info(&tbi) == 0);
+ tbi_float_val = tbi.numer;
+ tbi_float_val /= tbi.denom;
+ tbi_safe_math_max = UINT64_MAX / tbi.numer;
+
+ if (getpid() == 1) {
+ pid1_magic = true;
+ }
+
+ if (stat("/AppleInternal", &sb) == 0 && stat("/var/db/disableAppleInternal", &sb) == -1) {
+ do_apple_internal_logging = true;
+ }
+
+ if (stat("/var/db/.debug_launchd", &sb) == 0) {
+ internal_mask_pri = LOG_UPTO(LOG_DEBUG);
+ 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 ) {
+ 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 ) {
+ g_use_gmalloc = true;
+ }
+
+ 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;
+ if( r == 0 && strnstr(bootargs, "-v", len) != NULL ) {
+ g_verbose_boot = true;
+ }
+
+ if( pid1_magic && g_verbose_boot && stat("/var/db/.launchd_shutdown_debugging", &sb) == 0 ) {
+ g_shutdown_debugging = true;
+ }
+
+ if( stat("/var/db/.launchd_log_strict_usage", &sb) == 0 ) {
+ g_log_strict_usage = true;
+ }
}
#include <sys/types.h>
#include <bsm/libbsm.h>
#include <stdbool.h>
+#include <stdint.h>
+#include <float.h>
#include <syslog.h>
#include "launchd_runtime_kill.h"
+#include "launchd_ktrace.h"
+
+#if 0
+
+/* I need to do more testing of these macros */
+
+#define min_of_type(x) \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), long double), LDBL_MIN, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), double), DBL_MIN, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), float), FLT_MIN, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char), 0, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), signed char), INT8_MIN, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), short), INT16_MIN, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int), INT32_MIN, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), long), (__builtin_choose_expr(sizeof(x) == 4, INT32_MIN, INT64_MIN)), \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), long long), INT64_MIN, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), unsigned char), 0, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), unsigned short), 0, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), unsigned int), 0, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), unsigned long), 0, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), unsigned long long), 0, \
+ (void)0))))))))))))))
+
+#define max_of_type(x) \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), long double), LDBL_MAX, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), double), DBL_MAX, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), float), FLT_MAX, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char), UINT8_MAX, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), signed char), INT8_MAX, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), short), INT16_MIN, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int), INT32_MAX, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), long), (__builtin_choose_expr(sizeof(x) == 4, INT32_MAX, INT64_MAX)), \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), long long), INT64_MAX, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), unsigned char), UINT8_MAX, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), unsigned short), UINT16_MAX, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), unsigned int), UINT32_MAX, \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), unsigned long), (__builtin_choose_expr(sizeof(x) == 4, UINT32_MAX, UINT64_MAX)), \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), unsigned long long), UINT64_MAX, \
+ (void)0))))))))))))))
+
+#endif
+
+#define likely(x) __builtin_expect((bool)(x), true)
+#define unlikely(x) __builtin_expect((bool)(x), false)
struct ldcred {
uid_t euid;
gid_t egid;
gid_t gid;
pid_t pid;
- au_asid_t asid;
};
/*
* Use launchd_assert() for core initialization routines.
*/
#define launchd_assumes(e) \
- (__builtin_expect(!(e), 0) ? _log_launchd_bug(__rcs_file_version__, __FILE__, __LINE__, #e), false : true)
-
-#define launchd_blame(e, b) \
- (__builtin_expect(!(e), 0) ? syslog(LOG_DEBUG, "Encountered bug: %d", b), false : true)
+ (unlikely(!(e)) ? _log_launchd_bug(__rcs_file_version__, __FILE__, __LINE__, #e), false : true)
#define launchd_assert(e) if (__builtin_constant_p(e)) { char __compile_time_assert__[e ? 1 : -1] __attribute__((unused)); } else if (!launchd_assumes(e)) { abort(); }
-#define likely(x) __builtin_expect((bool)(x), true)
-#define unlikely(x) __builtin_expect((bool)(x), false)
-
void _log_launchd_bug(const char *rcs_rev, const char *path, unsigned int line, const char *test);
typedef void (*kq_callback)(void *, struct kevent *);
typedef boolean_t (*mig_callback)(mach_msg_header_t *, mach_msg_header_t *);
typedef void (*timeout_callback)(void);
+extern bool pid1_magic;
+extern bool low_level_debug;
+extern char g_username[128];
+extern char g_my_label[128];
+extern bool g_shutdown_debugging;
+extern bool g_verbose_boot;
+extern bool g_use_gmalloc;
+extern bool g_log_per_user_shutdown;
+extern bool g_log_strict_usage;
+extern bool g_embedded_shutdown_log;
+extern int32_t g_sync_frequency;
+extern pid_t g_wsp;
+
mach_port_t runtime_get_kernel_port(void);
+extern boolean_t launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply);
void runtime_add_ref(void);
void runtime_del_ref(void);
+void runtime_add_weak_ref(void);
+void runtime_del_weak_ref(void);
void launchd_runtime_init(void);
void launchd_runtime_init2(void);
void launchd_runtime(void) __attribute__((noreturn));
+void launchd_log_vm_stats(void);
+
int runtime_close(int fd);
int runtime_fsync(int fd);
void runtime_set_timeout(timeout_callback to_cb, unsigned int sec);
kern_return_t runtime_add_mport(mach_port_t name, mig_callback demux, mach_msg_size_t msg_size);
kern_return_t runtime_remove_mport(mach_port_t name);
-bool runtime_get_caller_creds(struct ldcred *ldc);
+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 *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);
+void log_kevent_struct(int level, struct kevent *kev_base, int indx);
pid_t runtime_fork(mach_port_t bsport);
+mach_msg_return_t launchd_exc_runtime_once(mach_port_t port, mach_msg_size_t rcv_msg_size, mach_msg_size_t send_msg_size, mig_reply_error_t *bufRequest, mig_reply_error_t *bufReply, mach_msg_timeout_t to);
+
kern_return_t runtime_log_forward(uid_t forward_uid, gid_t forward_gid, vm_offset_t inval, mach_msg_type_number_t invalCnt);
kern_return_t runtime_log_drain(mach_port_t srp, vm_offset_t *outval, mach_msg_type_number_t *outvalCnt);
-#define LOG_APPLEONLY 0x4141504c /* AAPL in hex */
+#define LOG_APPLEONLY 0x4141504c /* AAPL in hex */
+#define LOG_SCOLDING 0x3030493b
+#define LOG_CONSOLE (1 << 31)
struct runtime_syslog_attr {
const char *from_name;
void runtime_closelog(void);
void runtime_syslog(int pri, const char *message, ...) __attribute__((format(printf, 2, 3)));
void runtime_vsyslog(struct runtime_syslog_attr *attr, const char *message, va_list args) __attribute__((format(printf, 2, 0)));
+void runtime_log_push(void);
+int64_t runtime_get_wall_time(void) __attribute__((warn_unused_result));
+uint64_t runtime_get_opaque_time(void) __attribute__((warn_unused_result));
+uint64_t runtime_get_opaque_time_of_event(void) __attribute__((pure, warn_unused_result));
+uint64_t runtime_opaque_time_to_nano(uint64_t o) __attribute__((const, warn_unused_result));
+uint64_t runtime_get_nanoseconds_since(uint64_t o) __attribute__((pure, warn_unused_result));
kern_return_t launchd_set_bport(mach_port_t name);
kern_return_t launchd_get_bport(mach_port_t *name);
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_close_recv(mach_port_t name);
#endif
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
-static const char *const __rcs_file_version__ = "$Revision: 23792 $";
+static const char *const __rcs_file_version__ = "$Revision: 23921 $";
#include "config.h"
#include "launchd_unix_ipc.h"
+#include <sys/socket.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/event.h>
static launch_data_t adjust_rlimits(launch_data_t in);
static void ipc_readmsg2(launch_data_t data, const char *cmd, void *context);
+static void ipc_readmsg(launch_data_t msg, void *context);
static void ipc_listen_callback(void *obj __attribute__((unused)), struct kevent *kev);
static bool ipc_inited = false;
-void
+static void
ipc_clean_up(void)
{
if (ipc_self != getpid()) {
}
if (-1 == unlink(sockpath)) {
- runtime_syslog(LOG_WARNING, "unlink(\"%s\"): %m", sockpath);
+ runtime_syslog(LOG_WARNING, "unlink(\"%s\"): %s", sockpath, strerror(errno));
} else if (-1 == rmdir(sockdir)) {
- runtime_syslog(LOG_WARNING, "rmdir(\"%s\"): %m", sockdir);
+ runtime_syslog(LOG_WARNING, "rmdir(\"%s\"): %s", sockdir, strerror(errno));
}
}
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
- if (getpid() == 1) {
+ if (pid1_magic) {
strcpy(ourdir, LAUNCHD_SOCK_PREFIX);
strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path));
stat(ourdir, &sb);
if (!S_ISDIR(sb.st_mode)) {
errno = EEXIST;
- runtime_syslog(LOG_ERR, "mkdir(\"%s\"): %m", LAUNCHD_SOCK_PREFIX);
+ runtime_syslog(LOG_ERR, "mkdir(\"%s\"): %s", LAUNCHD_SOCK_PREFIX, strerror(errno));
goto out_bad;
}
} else {
- runtime_syslog(LOG_ERR, "mkdir(\"%s\"): %m", ourdir);
+ runtime_syslog(LOG_ERR, "mkdir(\"%s\"): %s", ourdir, strerror(errno));
goto out_bad;
}
}
} else {
- snprintf(ourdir, sizeof(ourdir), "/tmp/launchd-%u.XXXXXX", getpid());
- if (!launchd_assumes(mkdtemp(ourdir) != NULL)) {
+ snprintf(ourdir, sizeof(ourdir), _PATH_TMP "launchd-%u.XXXXXX", getpid());
+ if (mkdtemp(ourdir) == NULL) {
+ runtime_syslog(LOG_ERR, "Could not create critical directory \"%s\": %s", ourdir, strerror(errno));
goto out_bad;
}
snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/sock", ourdir);
if (unlink(sun.sun_path) == -1 && errno != ENOENT) {
if (errno != EROFS) {
- runtime_syslog(LOG_ERR, "unlink(\"thesocket\"): %m");
+ runtime_syslog(LOG_ERR, "unlink(\"thesocket\"): %s", strerror(errno));
}
goto out_bad;
}
if (r == -1) {
if (errno != EROFS) {
- runtime_syslog(LOG_ERR, "bind(\"thesocket\"): %m");
+ runtime_syslog(LOG_ERR, "bind(\"thesocket\"): %s", strerror(errno));
}
goto out_bad;
}
if (listen(fd, SOMAXCONN) == -1) {
- runtime_syslog(LOG_ERR, "listen(\"thesocket\"): %m");
+ runtime_syslog(LOG_ERR, "listen(\"thesocket\"): %s", strerror(errno));
goto out_bad;
}
if (kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &kqipc_listen_callback) == -1) {
- runtime_syslog(LOG_ERR, "kevent_mod(\"thesocket\", EVFILT_READ): %m");
+ runtime_syslog(LOG_ERR, "kevent_mod(\"thesocket\", EVFILT_READ): %s", strerror(errno));
goto out_bad;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
c->kqconn_callback = ipc_callback;
- c->conn = launchd_fdopen(fd);
+ if( j ) {
+ c->conn = launchd_fdopen(-1, fd);
+ } else {
+ c->conn = launchd_fdopen(fd, -1);
+ }
+
c->j = j;
LIST_INSERT_HEAD(&connections, c, sle);
kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &c->kqconn_callback);
if (kev->filter == EVFILT_READ) {
if (launchd_msg_recv(c->conn, ipc_readmsg, c) == -1 && errno != EAGAIN) {
if (errno != ECONNRESET) {
- runtime_syslog(LOG_DEBUG, "%s(): recv: %m", __func__);
+ runtime_syslog(LOG_DEBUG, "%s(): recv: %s", __func__, strerror(errno));
}
ipc_close(c);
}
r = launchd_msg_send(c->conn, NULL);
if (r == -1) {
if (errno != EAGAIN) {
- runtime_syslog(LOG_DEBUG, "%s(): send: %m", __func__);
+ runtime_syslog(LOG_DEBUG, "%s(): send: %s", __func__, strerror(errno));
ipc_close(c);
}
} else if (r == 0) {
}
}
-static void set_user_env(launch_data_t obj, const char *key, void *context __attribute__((unused)))
+static void
+set_user_env(launch_data_t obj, const char *key, void *context __attribute__((unused)))
{
- setenv(key, launch_data_get_string(obj), 1);
+ const char *v = launch_data_get_string(obj);
+ 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));
+ }
}
void
if (errno == EAGAIN) {
kevent_mod(launchd_getfd(rmc.c->conn), EVFILT_WRITE, EV_ADD, 0, 0, &rmc.c->kqconn_callback);
} else {
- runtime_syslog(LOG_DEBUG, "launchd_msg_send() == -1: %m");
+ runtime_syslog(LOG_DEBUG, "launchd_msg_send() == -1: %s", strerror(errno));
ipc_close(rmc.c);
}
}
launch_data_free(rmc.resp);
}
-
void
ipc_readmsg2(launch_data_t data, const char *cmd, void *context)
{
return;
}
- //job_log(rmc->c->j, LOG_DEBUG, "Unix IPC request: %s", cmd);
-
- if (data == NULL) {
- if (!strcmp(cmd, LAUNCH_KEY_CHECKIN)) {
- if (rmc->c->j) {
- resp = job_export(rmc->c->j);
- job_checkin(rmc->c->j);
- } else {
- resp = launch_data_new_errno(EACCES);
+// job_log(rmc->c->j, LOG_NOTICE, "Socket IPC request: %s.", cmd);
+
+ /* Do not allow commands other than check-in to come over the trusted socket
+ * on the Desktop. On Embedded, allow all commands over the trusted socket if
+ * the job has the God Mode key set.
+ */
+#if TARGET_OS_EMBEDDED
+ bool allow_privileged_ops = ( !rmc->c->j || job_is_god(rmc->c->j) );
+#else
+ bool allow_privileged_ops = !rmc->c->j;
+#endif
+
+ if( rmc->c->j && strcmp(cmd, LAUNCH_KEY_CHECKIN) == 0 ) {
+ resp = job_export(rmc->c->j);
+ job_checkin(rmc->c->j);
+ } else if( allow_privileged_ops ) {
+ #if TARGET_OS_EMBEDDED
+ g_embedded_privileged_action = rmc->c->j && job_is_god(rmc->c->j);
+ #endif
+ if( data == NULL ) {
+ if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) {
+ launchd_shutdown();
+ resp = launch_data_new_errno(0);
+ } else if (!strcmp(cmd, LAUNCH_KEY_SINGLEUSER)) {
+ launchd_single_user();
+ resp = launch_data_new_errno(0);
+ } else if (!strcmp(cmd, LAUNCH_KEY_GETJOBS)) {
+ resp = job_export_all();
+ ipc_revoke_fds(resp);
+ } else if (!strcmp(cmd, LAUNCH_KEY_GETRESOURCELIMITS)) {
+ resp = adjust_rlimits(NULL);
+ } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGESELF)) {
+ struct rusage rusage;
+ getrusage(RUSAGE_SELF, &rusage);
+ resp = launch_data_new_opaque(&rusage, sizeof(rusage));
+ } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGECHILDREN)) {
+ struct rusage rusage;
+ getrusage(RUSAGE_CHILDREN, &rusage);
+ resp = launch_data_new_opaque(&rusage, sizeof(rusage));
}
- } else if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) {
- launchd_shutdown();
- resp = launch_data_new_errno(0);
- } else if (!strcmp(cmd, LAUNCH_KEY_SINGLEUSER)) {
- launchd_single_user();
- resp = launch_data_new_errno(0);
- } else if (!strcmp(cmd, LAUNCH_KEY_GETJOBS)) {
- resp = job_export_all();
- ipc_revoke_fds(resp);
- } else if (!strcmp(cmd, LAUNCH_KEY_GETRESOURCELIMITS)) {
- resp = adjust_rlimits(NULL);
- } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGESELF)) {
- struct rusage rusage;
- getrusage(RUSAGE_SELF, &rusage);
- resp = launch_data_new_opaque(&rusage, sizeof(rusage));
- } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGECHILDREN)) {
- struct rusage rusage;
- getrusage(RUSAGE_CHILDREN, &rusage);
- resp = launch_data_new_opaque(&rusage, sizeof(rusage));
- }
- } else if (!strcmp(cmd, LAUNCH_KEY_STARTJOB)) {
- if ((j = job_find(launch_data_get_string(data))) != NULL) {
- job_dispatch(j, true);
- errno = 0;
- }
- resp = launch_data_new_errno(errno);
- } else if (!strcmp(cmd, LAUNCH_KEY_STOPJOB)) {
- if ((j = job_find(launch_data_get_string(data))) != NULL) {
- job_stop(j);
- errno = 0;
- }
- resp = launch_data_new_errno(errno);
- } else if (!strcmp(cmd, LAUNCH_KEY_REMOVEJOB)) {
- if ((j = job_find(launch_data_get_string(data))) != NULL) {
- job_remove(j);
- errno = 0;
- }
- resp = launch_data_new_errno(errno);
- } else if (!strcmp(cmd, LAUNCH_KEY_SUBMITJOB)) {
- if (launch_data_get_type(data) == LAUNCH_DATA_ARRAY) {
- resp = job_import_bulk(data);
} else {
- if (job_import(data)) {
- errno = 0;
+ if (!strcmp(cmd, LAUNCH_KEY_STARTJOB)) {
+ if ((j = job_find(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)) {
+ if ((j = job_find(launch_data_get_string(data))) != NULL) {
+ 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) {
+ errno = 0;
+ job_remove(j);
+ }
+ resp = launch_data_new_errno(errno);
+ } else if (!strcmp(cmd, LAUNCH_KEY_SUBMITJOB)) {
+ if (launch_data_get_type(data) == LAUNCH_DATA_ARRAY) {
+ resp = job_import_bulk(data);
+ } else {
+ if (job_import(data)) {
+ errno = 0;
+ }
+ resp = launch_data_new_errno(errno);
+ }
+ } else if (!strcmp(cmd, LAUNCH_KEY_UNSETUSERENVIRONMENT)) {
+ unsetenv(launch_data_get_string(data));
+ resp = launch_data_new_errno(0);
+ } else if (!strcmp(cmd, LAUNCH_KEY_SETUSERENVIRONMENT)) {
+ launch_data_dict_iterate(data, set_user_env, NULL);
+ resp = launch_data_new_errno(0);
+ } 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) {
+ resp = launch_data_new_errno(errno);
+ } else {
+ resp = job_export(j);
+ ipc_revoke_fds(resp);
+ }
+ } else if( !strcmp(cmd, LAUNCH_KEY_SETPRIORITYLIST) ) {
+ resp = launch_data_new_errno(launchd_set_jetsam_priorities(data));
}
- resp = launch_data_new_errno(errno);
- }
- } else if (!strcmp(cmd, LAUNCH_KEY_UNSETUSERENVIRONMENT)) {
- unsetenv(launch_data_get_string(data));
- resp = launch_data_new_errno(0);
- } else if (!strcmp(cmd, LAUNCH_KEY_SETUSERENVIRONMENT)) {
- launch_data_dict_iterate(data, set_user_env, NULL);
- resp = launch_data_new_errno(0);
- } 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) {
- resp = launch_data_new_errno(errno);
- } else {
- resp = job_export(j);
- ipc_revoke_fds(resp);
}
+ #if TARGET_OS_EMBEDDED
+ g_embedded_privileged_action = false;
+ #endif
+ } else {
+ resp = launch_data_new_errno(EACCES);
}
rmc->resp = resp;
}
+static int
+close_abi_fixup(int fd)
+{
+ return runtime_close(fd);
+}
+
void
ipc_close(struct conncb *c)
{
LIST_REMOVE(c, sle);
- launchd_close(c->conn, runtime_close);
+ launchd_close(c->conn, close_abi_fixup);
free(c);
}
continue;
}
- if (/* XXX readcfg_pid && */ getpid() == 1 && (i == RLIMIT_NOFILE || i == RLIMIT_NPROC)) {
+ if (/* XXX readcfg_pid && */ pid1_magic && (i == RLIMIT_NOFILE || i == RLIMIT_NPROC)) {
int gmib[] = { CTL_KERN, KERN_MAXPROC };
int pmib[] = { CTL_KERN, KERN_MAXPROCPERUID };
const char *gstr = "kern.maxproc";
gstr = "kern.maxfiles";
pstr = "kern.maxfilesperproc";
break;
- case RLIMIT_NPROC:
- /* kernel will not clamp to this value, we must */
- if (gval > 2500) {
- gval = 2500;
- }
- break;
default:
break;
}
void ipc_close_all_with_job(job_t j);
void ipc_close(struct conncb *c);
void ipc_callback(void *, struct kevent *);
-void ipc_readmsg(launch_data_t msg, void *context);
void ipc_revoke_fds(launch_data_t o);
void ipc_close_fds(launch_data_t o);
-void ipc_clean_up(void);
void ipc_server_init(void);
#endif
{
struct timespec timeout = { 10, 0 };
struct sockaddr_storage ss;
- socklen_t slen = sizeof(ss);
+ socklen_t slen = (socklen_t)sizeof ss;
struct kevent kev;
int r, ec = EXIT_FAILURE;
launch_data_t tmp, resp, msg = launch_data_alloc(LAUNCH_DATA_STRING);
}
if (w) {
- dup2(kev.ident, STDIN_FILENO);
+ dup2((int)kev.ident, STDIN_FILENO);
if (dupstdout)
- dup2(kev.ident, STDOUT_FILENO);
+ dup2((int)kev.ident, STDOUT_FILENO);
if (dupstderr)
- dup2(kev.ident, STDERR_FILENO);
+ dup2((int)kev.ident, STDERR_FILENO);
execv(prog, argv + 1);
syslog(LOG_ERR, "execv(): %m");
exit(EXIT_FAILURE);
}
- if ((r = accept(kev.ident, (struct sockaddr *)&ss, &slen)) == -1) {
+ if ((r = accept((int)kev.ident, (struct sockaddr *)&ss, &slen)) == -1) {
if (errno == EWOULDBLOCK)
continue;
- syslog(LOG_DEBUG, "accept(): %m");
+ syslog(LOG_WARNING, "accept(): %m");
goto out;
} else {
- char fromhost[NI_MAXHOST];
- char fromport[NI_MAXSERV];
- int gni_r;
-
- gni_r = getnameinfo((struct sockaddr *)&ss, slen,
- fromhost, sizeof(fromhost),
- fromport, sizeof(fromport),
- NI_NUMERICHOST | NI_NUMERICSERV);
-
- if (gni_r) {
- syslog(LOG_WARNING, "%s: getnameinfo(): %s", prog, gai_strerror(gni_r));
+ if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
+ char fromhost[NI_MAXHOST];
+ char fromport[NI_MAXSERV];
+ int gni_r;
+
+ gni_r = getnameinfo((struct sockaddr *)&ss, slen,
+ fromhost, (socklen_t) sizeof fromhost,
+ fromport, (socklen_t) sizeof fromport,
+ NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if (gni_r) {
+ syslog(LOG_WARNING, "%s: getnameinfo(): %s", prog, gai_strerror(gni_r));
+ } else {
+ syslog(LOG_INFO, "%s: Connection from: %s on port: %s", prog, fromhost, fromport);
+ }
} else {
- syslog(LOG_INFO, "%s: Connection from: %s on port: %s", prog, fromhost, fromport);
+ syslog(LOG_WARNING, "%s: getnameinfo() only supports IPv4/IPv6. Connection from address family: %u", prog, ss.ss_family);
}
switch (fork()) {
case -1:
syslog(LOG_WARNING, "fork(): %m");
+ if( errno != ENOMEM ) {
+ continue;
+ }
goto out;
case 0:
break;
*/
#include "config.h"
+#include "launch.h"
+#include "launch_priv.h"
#include "bootstrap.h"
#include "bootstrap_priv.h"
-
#include "vproc.h"
#include "vproc_priv.h"
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)
{
- return vproc_mig_create_server(bp, server_cmd, server_uid, on_demand, server_port);
+ kern_return_t kr;
+
+ kr = vproc_mig_create_server(bp, server_cmd, server_uid, on_demand, server_port);
+
+ if (kr == VPROC_ERR_TRY_PER_USER) {
+ mach_port_t puc;
+
+ if (vproc_mig_lookup_per_user_context(bp, 0, &puc) == 0) {
+ kr = vproc_mig_create_server(puc, server_cmd, server_uid, on_demand, server_port);
+ mach_port_deallocate(mach_task_self(), puc);
+ }
+ }
+
+ return kr;
}
kern_return_t
return vproc_mig_parent(bp, parent_port);
}
-kern_return_t
-bootstrap_set_policy(mach_port_t bp, pid_t target_pid, uint64_t flags, const char *target_service)
-{
- return vproc_mig_set_service_policy(bp, target_pid, flags, target_service ? (char *)target_service : "");
-}
-
kern_return_t
bootstrap_register(mach_port_t bp, name_t service_name, mach_port_t sp)
{
kern_return_t
bootstrap_create_service(mach_port_t bp, name_t service_name, mach_port_t *sp)
{
- return vproc_mig_create_service(bp, service_name, sp);
+ kern_return_t kr;
+
+ if ((kr = bootstrap_check_in(bp, service_name, sp))) {
+ return kr;
+ }
+
+ if ((kr = mach_port_mod_refs(mach_task_self(), *sp, MACH_PORT_RIGHT_RECEIVE, -1))) {
+ return kr;
+ }
+
+ return bootstrap_look_up(bp, service_name, sp);
}
kern_return_t
-bootstrap_check_in(mach_port_t bp, name_t service_name, mach_port_t *sp)
+bootstrap_check_in(mach_port_t bp, const name_t service_name, mach_port_t *sp)
{
- return vproc_mig_check_in(bp, service_name, sp);
+ return vproc_mig_check_in2(bp, (char *)service_name, sp, 0);
}
kern_return_t
-bootstrap_look_up_per_user(mach_port_t bp, name_t service_name, uid_t target_user, mach_port_t *sp)
+bootstrap_check_in2(mach_port_t bp, const name_t service_name, mach_port_t *sp, uint64_t flags)
{
- struct stat sb;
+ return vproc_mig_check_in2(bp, (char *)service_name, sp, flags);
+}
+
+kern_return_t
+bootstrap_look_up_per_user(mach_port_t bp, const name_t service_name, uid_t target_user, mach_port_t *sp)
+{
+ audit_token_t au_tok;
kern_return_t kr;
mach_port_t puc;
- if (pthread_main_np() && (stat("/AppleInternal", &sb) != -1)) {
- _vproc_log(LOG_WARNING, "Please review the comments in 4890134.");
- }
+ /* See rdar://problem/4890134. */
if ((kr = vproc_mig_lookup_per_user_context(bp, target_user, &puc)) != 0) {
return kr;
}
- kr = vproc_mig_look_up2(puc, service_name, sp, 0, 0);
- mach_port_deallocate(mach_task_self(), puc);
+ if( !service_name ) {
+ *sp = puc;
+ } else {
+ kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, 0, 0);
+ mach_port_deallocate(mach_task_self(), puc);
+ }
return kr;
}
+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)
+{
+ mach_msg_type_number_t junk = 0;
+ return vproc_mig_lookup_children(bp, children, &junk, names, n_children, properties, &junk);
+}
kern_return_t
-bootstrap_look_up(mach_port_t bp, name_t service_name, mach_port_t *sp)
+bootstrap_look_up(mach_port_t bp, const name_t service_name, mach_port_t *sp)
{
return bootstrap_look_up2(bp, service_name, sp, 0, 0);
}
kern_return_t
-bootstrap_look_up2(mach_port_t bp, name_t service_name, mach_port_t *sp, pid_t target_pid, uint64_t flags)
+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 kr;
+ 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;
+ 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;
-
- if ((kr = vproc_mig_look_up2(bp, service_name, sp, target_pid, flags)) != VPROC_ERR_TRY_PER_USER) {
- return kr;
+
+ 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) {
+ goto out;
+ }
+
if ((kr = vproc_mig_lookup_per_user_context(bp, 0, &puc)) != 0) {
- return kr;
+ goto out;
}
-
- kr = vproc_mig_look_up2(puc, service_name, sp, target_pid, flags);
+
+ kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, target_pid, flags);
mach_port_deallocate(mach_task_self(), puc);
-
+
+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;
+
+ /*
+ * The audit token magic is dependent on the per-user launchd
+ * forwarding MIG requests to the root launchd when it cannot
+ * find the answer locally.
+ */
+
+ /* This API should be in Libsystem, but is not */
+ //audit_token_to_au32(au_tok, NULL, &server_euid, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ server_euid = au_tok.val[1];
+
+ if (server_euid) {
+ mach_port_deallocate(mach_task_self(), *sp);
+ kr = BOOTSTRAP_NOT_PRIVILEGED;
+ }
+ }
+ /* If performance becomes a problem, we should restructure this. */
+ pthread_mutex_unlock(&bslu2_lock);
+
return kr;
}
kern_return_t
bootstrap_status(mach_port_t bp, name_t service_name, bootstrap_status_t *service_active)
{
+ kern_return_t kr;
mach_port_t p;
+ if ((kr = bootstrap_look_up(bp, service_name, &p))) {
+ return kr;
+ }
+
+ mach_port_deallocate(mach_task_self(), p);
+ *service_active = BOOTSTRAP_STATUS_ACTIVE;
+
if (bootstrap_check_in(bp, service_name, &p) == BOOTSTRAP_SUCCESS) {
mach_port_mod_refs(mach_task_self(), p, MACH_PORT_RIGHT_RECEIVE, -1);
*service_active = BOOTSTRAP_STATUS_ON_DEMAND;
- return BOOTSTRAP_SUCCESS;
- } else if (bootstrap_look_up(bp, service_name, &p) == BOOTSTRAP_SUCCESS) {
- mach_port_deallocate(mach_task_self(), p);
- *service_active = BOOTSTRAP_STATUS_ACTIVE;
- return BOOTSTRAP_SUCCESS;
}
- return BOOTSTRAP_UNKNOWN_SERVICE;
+ return BOOTSTRAP_SUCCESS;
}
kern_return_t
bootstrap_info(mach_port_t bp,
- name_array_t *service_names, mach_msg_type_number_t *service_namesCnt,
- bootstrap_status_array_t *service_active, mach_msg_type_number_t *service_activeCnt)
+ name_array_t *service_names, mach_msg_type_number_t *service_namesCnt,
+ name_array_t *service_jobs, mach_msg_type_number_t *service_jobsCnt,
+ bootstrap_status_array_t *service_active, mach_msg_type_number_t *service_activeCnt,
+ uint64_t flags)
{
- return vproc_mig_info(bp, service_names, service_namesCnt,
- service_active, service_activeCnt);
+ return vproc_mig_info(bp, service_names, service_namesCnt, service_jobs, service_jobsCnt, service_active, service_activeCnt, flags);
}
const char *
#include "launch.h"
#include "launch_priv.h"
#include "launch_internal.h"
+#include "launchd_ktrace.h"
#include <mach/mach.h>
#include <libkern/OSByteOrder.h>
#include <errno.h>
#include <pwd.h>
#include <assert.h>
+#include <uuid/uuid.h>
+#include <sys/syscall.h>
+
+#ifdef __LP64__
+/* workaround: 5723161 */
+#ifndef __DARWIN_ALIGN32
+#define __DARWIN_ALIGN32(x) (((size_t)(x) + 3) & ~3)
+#endif
+#undef CMSG_DATA
+#define CMSG_DATA(cmsg) \
+ ((uint8_t *)(cmsg) + __DARWIN_ALIGN32(sizeof(struct cmsghdr)))
+#undef CMSG_SPACE
+#define CMSG_SPACE(l) \
+ (__DARWIN_ALIGN32(sizeof(struct cmsghdr)) + __DARWIN_ALIGN32(l))
+#undef CMSG_LEN
+#define CMSG_LEN(l) \
+ (__DARWIN_ALIGN32(sizeof(struct cmsghdr)) + (l))
+#endif
#include "bootstrap.h"
#include "vproc.h"
*/
extern void __OSBogusByteSwap__(void);
-#define host2big(x) \
+#define host2wire(x) \
({ typeof (x) _X, _x = (x); \
switch (sizeof(_x)) { \
case 8: \
- _X = OSSwapHostToBigInt64(_x); \
+ _X = OSSwapHostToLittleInt64(_x); \
break; \
case 4: \
- _X = OSSwapHostToBigInt32(_x); \
+ _X = OSSwapHostToLittleInt32(_x); \
break; \
case 2: \
- _X = OSSwapHostToBigInt16(_x); \
+ _X = OSSwapHostToLittleInt16(_x); \
break; \
case 1: \
_X = _x; \
})
-#define big2host(x) \
+#define big2wire(x) \
({ typeof (x) _X, _x = (x); \
switch (sizeof(_x)) { \
case 8: \
- _X = OSSwapBigToHostInt64(_x); \
+ _X = OSSwapLittleToHostInt64(_x); \
break; \
case 4: \
- _X = OSSwapBigToHostInt32(_x); \
+ _X = OSSwapLittleToHostInt32(_x); \
break; \
case 2: \
- _X = OSSwapBigToHostInt16(_x); \
+ _X = OSSwapLittleToHostInt16(_x); \
break; \
case 1: \
_X = _x; \
uint64_t opaque_size;
};
};
- int fd;
- mach_port_t mp;
- int err;
- long long number;
- uint32_t boolean; /* We'd use 'bool' but this struct needs to be used under Rosetta, and sizeof(bool) is different between PowerPC and Intel */
+ 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,
+};
struct _launch {
void *sendbuf;
int *sendfds;
size_t sendfdcnt;
size_t recvlen;
size_t recvfdcnt;
+ int which;
+ int cifd;
int fd;
};
static launch_data_t launch_msg_internal(launch_data_t d);
static void launch_mach_checkin_service(launch_data_t obj, const char *key, void *context);
+static int64_t s_am_embedded_god = false;
static launch_t in_flight_msg_recv_client;
static pthread_once_t _lc_once = PTHREAD_ONCE_INIT;
+bool do_apple_internal_logging = false;
+
static struct _launch_client {
pthread_mutex_t mtx;
launch_t l;
struct sockaddr_un sun;
char *where = getenv(LAUNCHD_SOCKET_ENV);
char *_launchd_fd = getenv(LAUNCHD_TRUSTED_FD_ENV);
- int dfd, lfd = -1;
+ int dfd, lfd = -1, cifd = -1;
name_t spath;
_lc = calloc(1, sizeof(struct _launch_client));
-
+
if (!_lc)
return;
-
+
pthread_mutex_init(&_lc->mtx, NULL);
-
+
if (_launchd_fd) {
- lfd = strtol(_launchd_fd, NULL, 10);
- if ((dfd = dup(lfd)) >= 0) {
+ cifd = strtol(_launchd_fd, NULL, 10);
+ if ((dfd = dup(cifd)) >= 0) {
close(dfd);
- _fd(lfd);
+ _fd(cifd);
} else {
- lfd = -1;
+ cifd = -1;
}
unsetenv(LAUNCHD_TRUSTED_FD_ENV);
}
- if (lfd == -1) {
- memset(&sun, 0, sizeof(sun));
- sun.sun_family = AF_UNIX;
+
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+
+ /* The rules are as follows.
+ * - All users (including root) talk to their per-user launchd's by default.
+ * - If we have been invoked under sudo, talk to the system launchd.
+ * - If we're the root user and the __USE_SYSTEM_LAUNCHD environment variable is set, then
+ * talk to the system launchd.
+ */
+ 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 ) {
+ /* Talk to the system launchd. */
+ strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path));
+ } else {
+ /* Talk to our per-user launchd. */
+ size_t min_len;
+
+ min_len = sizeof(sun.sun_path) < sizeof(spath) ? sizeof(sun.sun_path) : sizeof(spath);
+
+ strncpy(sun.sun_path, spath, min_len);
+ }
+ }
+ }
- if (where && where[0] != '\0') {
- strncpy(sun.sun_path, where, sizeof(sun.sun_path));
- } else if (!getenv("SUDO_COMMAND") && _vprocmgr_getsocket(spath) == 0) {
- size_t min_len;
-
- min_len = sizeof(sun.sun_path) < sizeof(spath) ? sizeof(sun.sun_path) : sizeof(spath);
-
- strncpy(sun.sun_path, spath, min_len);
+ if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) {
+ goto out_bad;
+ }
+
+#if TARGET_OS_EMBEDDED
+ (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 ) {
+ /* 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
+ * adequate for clients' expectations.
+ */
+ close(lfd);
+ lfd = -1;
} else {
- strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path));
- }
-
- if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1)
- goto out_bad;
- if (-1 == connect(lfd, (struct sockaddr *)&sun, sizeof(sun)))
goto out_bad;
+ }
}
- if (!(_lc->l = launchd_fdopen(lfd)))
+
+ if (!(_lc->l = launchd_fdopen(lfd, cifd))) {
goto out_bad;
- if (!(_lc->async_resp = launch_data_alloc(LAUNCH_DATA_ARRAY)))
+ }
+
+ if (!(_lc->async_resp = launch_data_alloc(LAUNCH_DATA_ARRAY))) {
goto out_bad;
-
+ }
+
return;
out_bad:
if (_lc->l)
launchd_close(_lc->l, close);
else if (lfd != -1)
close(lfd);
+ if( cifd != -1 ) {
+ close(cifd);
+ }
if (_lc)
free(_lc);
_lc = NULL;
return dict->_array_cnt / 2;
}
-
bool
launch_data_dict_insert(launch_data_t dict, launch_data_t what, const char *key)
{
{
size_t i;
- if (LAUNCH_DATA_DICTIONARY != dict->type)
+ if (LAUNCH_DATA_DICTIONARY != dict->type) {
return;
+ }
- for (i = 0; i < dict->_array_cnt; i += 2)
+ for (i = 0; i < dict->_array_cnt; i += 2) {
cb(dict->_array[i + 1], dict->_array[i]->string, context);
+ }
}
bool
where->_array_cnt = ind + 1;
}
- if (where->_array[ind])
+ if (where->_array[ind]) {
launch_data_free(where->_array[ind]);
+ }
+
where->_array[ind] = what;
return true;
}
launch_data_t
launch_data_array_get_index(launch_data_t where, size_t ind)
{
- if (LAUNCH_DATA_ARRAY != where->type)
+ if (LAUNCH_DATA_ARRAY != where->type || ind >= where->_array_cnt) {
return NULL;
- if (ind < where->_array_cnt)
+ } else {
return where->_array[ind];
- return NULL;
+ }
}
launch_data_t
int
launchd_getfd(launch_t l)
{
- return l->fd;
+ return ( l->which == LAUNCHD_USE_CHECKIN_FD ) ? l->cifd : l->fd;
}
launch_t
-launchd_fdopen(int fd)
+launchd_fdopen(int fd, int cifd)
{
launch_t c;
return NULL;
c->fd = fd;
+ c->cifd = cifd;
+
+ if( c->fd == -1 || (c->fd != -1 && c->cifd != -1) ) {
+ c->which = LAUNCHD_USE_CHECKIN_FD;
+ } else if( c->cifd == -1 ) {
+ c->which = LAUNCHD_USE_OTHER_FD;
+ }
fcntl(fd, F_SETFL, O_NONBLOCK);
+ fcntl(cifd, F_SETFL, O_NONBLOCK);
if ((c->sendbuf = malloc(0)) == NULL)
goto out_bad;
if (lh->recvfds)
free(lh->recvfds);
closefunc(lh->fd);
+ closefunc(lh->cifd);
free(lh);
}
launch_data_pack(launch_data_t d, void *where, size_t len, int *fd_where, size_t *fd_cnt)
{
launch_data_t o_in_w = where;
- size_t i, rsz, total_data_len = sizeof(struct _launch_data);
+ size_t i, rsz, node_data_len = sizeof(struct _launch_data);
- if (total_data_len > len) {
+ if (node_data_len > len) {
return 0;
}
- where += total_data_len;
+ where += node_data_len;
- o_in_w->type = host2big(d->type);
+ o_in_w->type = host2wire(d->type);
+ size_t pad_len = 0;
switch (d->type) {
case LAUNCH_DATA_INTEGER:
- o_in_w->number = host2big(d->number);
+ o_in_w->number = host2wire(d->number);
break;
case LAUNCH_DATA_REAL:
- o_in_w->float_num = host2big(d->float_num);
+ o_in_w->float_num = host2wire(d->float_num);
break;
case LAUNCH_DATA_BOOL:
- o_in_w->boolean = host2big(d->boolean);
+ o_in_w->boolean = host2wire(d->boolean);
break;
case LAUNCH_DATA_ERRNO:
- o_in_w->err = host2big(d->err);
+ o_in_w->err = host2wire(d->err);
break;
case LAUNCH_DATA_FD:
- o_in_w->fd = host2big(d->fd);
+ o_in_w->fd = host2wire(d->fd);
if (fd_where && d->fd != -1) {
fd_where[*fd_cnt] = d->fd;
(*fd_cnt)++;
}
break;
case LAUNCH_DATA_STRING:
- o_in_w->string_len = host2big(d->string_len);
- total_data_len += ROUND_TO_64BIT_WORD_SIZE(strlen(d->string) + 1);
- if (total_data_len > len) {
+ o_in_w->string_len = host2wire(d->string_len);
+ node_data_len += ROUND_TO_64BIT_WORD_SIZE(d->string_len + 1);
+
+ if (node_data_len > len) {
return 0;
}
- memcpy(where, d->string, strlen(d->string) + 1);
+ memcpy(where, d->string, d->string_len + 1);
+
+ /* Zero padded data. */
+ pad_len = ROUND_TO_64BIT_WORD_SIZE(d->string_len + 1) - (d->string_len + 1);
+ bzero(where + d->string_len + 1, pad_len);
+
break;
case LAUNCH_DATA_OPAQUE:
- o_in_w->opaque_size = host2big(d->opaque_size);
- total_data_len += ROUND_TO_64BIT_WORD_SIZE(d->opaque_size);
- if (total_data_len > len) {
+ o_in_w->opaque_size = host2wire(d->opaque_size);
+ node_data_len += ROUND_TO_64BIT_WORD_SIZE(d->opaque_size);
+ if (node_data_len > len) {
return 0;
}
memcpy(where, d->opaque, d->opaque_size);
+
+ /* Zero padded data. */
+ pad_len = ROUND_TO_64BIT_WORD_SIZE(d->opaque_size) - d->opaque_size;
+ bzero(where + d->opaque_size, pad_len);
+
break;
case LAUNCH_DATA_DICTIONARY:
case LAUNCH_DATA_ARRAY:
- o_in_w->_array_cnt = host2big(d->_array_cnt);
- total_data_len += d->_array_cnt * sizeof(uint64_t);
- if (total_data_len > len) {
+ o_in_w->_array_cnt = host2wire(d->_array_cnt);
+ node_data_len += d->_array_cnt * sizeof(uint64_t);
+ if (node_data_len > len) {
return 0;
}
where += d->_array_cnt * sizeof(uint64_t);
for (i = 0; i < d->_array_cnt; i++) {
- rsz = launch_data_pack(d->_array[i], where, len - total_data_len, fd_where, fd_cnt);
+ rsz = launch_data_pack(d->_array[i], where, len - node_data_len, fd_where, fd_cnt);
if (rsz == 0) {
return 0;
}
where += rsz;
- total_data_len += rsz;
+ node_data_len += rsz;
}
break;
default:
break;
}
- return total_data_len;
+ return node_data_len;
}
launch_data_t
return NULL;
*data_offset += sizeof(struct _launch_data);
- switch (big2host(r->type)) {
+ switch (big2wire(r->type)) {
case LAUNCH_DATA_DICTIONARY:
case LAUNCH_DATA_ARRAY:
- tmpcnt = big2host(r->_array_cnt);
+ tmpcnt = big2wire(r->_array_cnt);
if ((data_size - *data_offset) < (tmpcnt * sizeof(uint64_t))) {
errno = EAGAIN;
return NULL;
r->_array_cnt = tmpcnt;
break;
case LAUNCH_DATA_STRING:
- tmpcnt = big2host(r->string_len);
+ tmpcnt = big2wire(r->string_len);
if ((data_size - *data_offset) < (tmpcnt + 1)) {
errno = EAGAIN;
return NULL;
*data_offset += ROUND_TO_64BIT_WORD_SIZE(tmpcnt + 1);
break;
case LAUNCH_DATA_OPAQUE:
- tmpcnt = big2host(r->opaque_size);
+ tmpcnt = big2wire(r->opaque_size);
if ((data_size - *data_offset) < tmpcnt) {
errno = EAGAIN;
return NULL;
}
break;
case LAUNCH_DATA_INTEGER:
- r->number = big2host(r->number);
+ r->number = big2wire(r->number);
break;
case LAUNCH_DATA_REAL:
- r->float_num = big2host(r->float_num);
+ r->float_num = big2wire(r->float_num);
break;
case LAUNCH_DATA_BOOL:
- r->boolean = big2host(r->boolean);
+ r->boolean = big2wire(r->boolean);
break;
case LAUNCH_DATA_ERRNO:
- r->err = big2host(r->err);
+ r->err = big2wire(r->err);
case LAUNCH_DATA_MACHPORT:
break;
default:
break;
}
- r->type = big2host(r->type);
+ r->type = big2wire(r->type);
return r;
}
-int launchd_msg_send(launch_t lh, launch_data_t d)
+int
+launchd_msg_send(launch_t lh, launch_data_t d)
{
struct launch_msg_header lmh;
struct cmsghdr *cm = NULL;
size_t sentctrllen = 0;
int r;
+ int fd2use = launchd_getfd(lh);
+ if( fd2use == -1 ) {
+ errno = EPERM;
+ return -1;
+ }
+
memset(&mh, 0, sizeof(mh));
/* confirm that the next hack works */
lh->sendfdcnt = fd_slots_used;
- msglen = lh->sendlen + sizeof(struct launch_msg_header); /* type promotion to make the host2big() macro work right */
- lmh.len = host2big(msglen);
- lmh.magic = host2big(LAUNCH_MSG_HEADER_MAGIC);
+ msglen = lh->sendlen + sizeof(struct launch_msg_header); /* type promotion to make the host2wire() macro work right */
+ lmh.len = host2wire(msglen);
+ lmh.magic = host2wire(LAUNCH_MSG_HEADER_MAGIC);
iov[0].iov_base = &lmh;
iov[0].iov_len = sizeof(lmh);
memcpy(CMSG_DATA(cm), lh->sendfds, lh->sendfdcnt * sizeof(int));
}
- if ((r = sendmsg(lh->fd, &mh, 0)) == -1) {
+ if ((r = sendmsg(fd2use, &mh, 0)) == -1) {
return -1;
} else if (r == 0) {
errno = ECONNRESET;
return 0;
}
-
int
launch_get_fd(void)
{
return r;
}
+extern kern_return_t vproc_mig_set_security_session(mach_port_t, uuid_t, mach_port_t);
+
+static inline bool
+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) ) {
+ uuid_t existing_uuid;
+ memcpy(existing_uuid, launch_data_get_opaque(d), sizeof(uuid_t));
+
+ /* A NULL UUID tells us to keep the session inherited from the parent. */
+ result = (bool)uuid_is_null(existing_uuid);
+ }
+
+ return result;
+}
+
launch_data_t
launch_msg_internal(launch_data_t d)
{
}
pthread_once(&_lc_once, launch_client_init);
-
if (!_lc) {
errno = ENOTCONN;
return NULL;
}
+ 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 ) {
+ _lc->l->which = LAUNCHD_USE_CHECKIN_FD;
+ } else {
+ _lc->l->which = LAUNCHD_USE_OTHER_FD;
+ }
+
+ fd2use = launchd_getfd(_lc->l);
+
+ if( fd2use == -1 ) {
+ errno = EPERM;
+ return NULL;
+ }
+
+#if !TARGET_OS_EMBEDDED
+ 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 ) {
+ launch_data_t v = launch_data_dict_lookup(d, LAUNCH_KEY_SUBMITJOB);
+
+ 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);
+ for( i = 0; i < cnt; i++ ) {
+ launch_data_t ji = launch_data_array_get_index(v, i);
+ if( launch_data_get_type(ji) == LAUNCH_DATA_DICTIONARY ) {
+ launch_data_t existing_v = launch_data_dict_lookup(ji, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
+ 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++;
+ } else if( launch_data_get_type(existing_v) == LAUNCH_DATA_OPAQUE ) {
+ jobs_that_need_sessions += uuid_data_is_null(existing_v) ? 0 : 1;
+ }
+ }
+ }
+ } else if( v && launch_data_get_type(v) == LAUNCH_DATA_DICTIONARY ) {
+ launch_data_t existing_v = launch_data_dict_lookup(v, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
+ 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);
+ jobs_that_need_sessions++;
+ } else {
+ jobs_that_need_sessions += uuid_data_is_null(existing_v) ? 0 : 1;
+ }
+ }
+ }
+#endif
+
pthread_mutex_lock(&_lc->mtx);
if (d && launchd_msg_send(_lc->l, d) == -1) {
goto out;
} while (launchd_msg_send(_lc->l, NULL) == -1);
}
-
+
while (resp == NULL) {
if (d == NULL && launch_data_array_get_count(_lc->async_resp) > 0) {
resp = launch_data_array_pop_first(_lc->async_resp);
fd_set rfds;
FD_ZERO(&rfds);
- FD_SET(_lc->l->fd, &rfds);
+ FD_SET(fd2use, &rfds);
- select(_lc->l->fd + 1, &rfds, NULL, NULL, NULL);
+ select(fd2use + 1, &rfds, NULL, NULL, NULL);
}
}
}
out:
+#if !TARGET_OS_EMBEDDED
+ 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;
+ if( resp_type == LAUNCH_DATA_ERRNO ) {
+ set_session = ( launch_data_get_errno(resp) == ENEEDAUTH );
+ } else if( resp_type == LAUNCH_DATA_ARRAY ) {
+ set_session = true;
+ }
+
+ kern_return_t kr = KERN_FAILURE;
+ if( set_session ) {
+ kr = vproc_mig_set_security_session(bootstrap_port, uuid, session_port);
+ }
+
+ if( kr == KERN_SUCCESS ) {
+ if( resp_type == LAUNCH_DATA_ERRNO ) {
+ launch_data_set_errno(resp, 0);
+ } else {
+ size_t i = 0;
+ 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;
+ 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);
+ }
+ }
+ }
+ }
+
+ mach_port_deallocate(mach_task_self(), session_port);
+ }
+#endif
+
pthread_mutex_unlock(&_lc->mtx);
return resp;
}
-int launchd_msg_recv(launch_t lh, void (*cb)(launch_data_t, void *), void *context)
+int
+launchd_msg_recv(launch_t lh, void (*cb)(launch_data_t, void *), void *context)
{
struct cmsghdr *cm = alloca(4096);
launch_data_t rmsg = NULL;
struct iovec iov;
int r;
+ int fd2use = launchd_getfd(lh);
+ if( fd2use == -1 ) {
+ errno = EPERM;
+ return -1;
+ }
+
memset(&mh, 0, sizeof(mh));
mh.msg_iov = &iov;
mh.msg_iovlen = 1;
mh.msg_control = cm;
mh.msg_controllen = 4096;
- if ((r = recvmsg(lh->fd, &mh, 0)) == -1)
+ if ((r = recvmsg(fd2use, &mh, 0)) == -1)
return -1;
if (r == 0) {
errno = ECONNRESET;
if (lh->recvlen < sizeof(struct launch_msg_header))
goto need_more_data;
- tmplen = big2host(lmhp->len);
+ tmplen = big2wire(lmhp->len);
- if (big2host(lmhp->magic) != LAUNCH_MSG_HEADER_MAGIC || tmplen <= sizeof(struct launch_msg_header)) {
+ if (big2wire(lmhp->magic) != LAUNCH_MSG_HEADER_MAGIC || tmplen <= sizeof(struct launch_msg_header)) {
errno = EBADRPC;
goto out_bad;
}
return -1;
}
-launch_data_t launch_data_copy(launch_data_t o)
+launch_data_t
+launch_data_copy(launch_data_t o)
{
launch_data_t r = launch_data_alloc(o->type);
size_t i;
return false;
}
-static int _fd(int fd)
+int
+_fd(int fd)
{
if (fd >= 0)
fcntl(fd, F_SETFD, 1);
return fd;
}
-launch_data_t launch_data_new_errno(int e)
+launch_data_t
+launch_data_new_errno(int e)
{
launch_data_t r = launch_data_alloc(LAUNCH_DATA_ERRNO);
return r;
}
-launch_data_t launch_data_new_fd(int fd)
+launch_data_t
+launch_data_new_fd(int fd)
{
launch_data_t r = launch_data_alloc(LAUNCH_DATA_FD);
return r;
}
-launch_data_t launch_data_new_machport(mach_port_t p)
+launch_data_t
+launch_data_new_machport(mach_port_t p)
{
launch_data_t r = launch_data_alloc(LAUNCH_DATA_MACHPORT);
return r;
}
-launch_data_t launch_data_new_integer(long long n)
+launch_data_t
+launch_data_new_integer(long long n)
{
launch_data_t r = launch_data_alloc(LAUNCH_DATA_INTEGER);
return r;
}
-launch_data_t launch_data_new_bool(bool b)
+launch_data_t
+launch_data_new_bool(bool b)
{
launch_data_t r = launch_data_alloc(LAUNCH_DATA_BOOL);
return r;
}
-launch_data_t launch_data_new_real(double d)
+launch_data_t
+launch_data_new_real(double d)
{
launch_data_t r = launch_data_alloc(LAUNCH_DATA_REAL);
return r;
}
-launch_data_t launch_data_new_string(const char *s)
+launch_data_t
+launch_data_new_string(const char *s)
{
launch_data_t r = launch_data_alloc(LAUNCH_DATA_STRING);
return r;
}
-launch_data_t launch_data_new_opaque(const void *o, size_t os)
+launch_data_t
+launch_data_new_opaque(const void *o, size_t os)
{
launch_data_t r = launch_data_alloc(LAUNCH_DATA_OPAQUE);
void
load_launchd_jobs_at_loginwindow_prompt(int flags __attribute__((unused)), ...)
{
- _vprocmgr_init("LoginWindow");
+ _vprocmgr_init(VPROCMGR_SESSION_LOGINWINDOW);
}
pid_t
-create_and_switch_to_per_session_launchd(const char *login __attribute__((unused)), int flags __attribute__((unused)), ...)
+create_and_switch_to_per_session_launchd(const char *login __attribute__((unused)), int flags, ...)
{
- mach_port_t bezel_ui_server;
- struct stat sb;
uid_t target_user = geteuid() ? geteuid() : getuid();
-
- if (_vprocmgr_move_subset_to_user(target_user, "Aqua")) {
+ if (_vprocmgr_move_subset_to_user(target_user, VPROCMGR_SESSION_AQUA, flags)) {
return -1;
}
-#define BEZEL_UI_PATH "/System/Library/LoginPlugins/BezelServices.loginPlugin/Contents/Resources/BezelUI/BezelUIServer"
-#define BEZEL_UI_PLIST "/System/Library/LaunchAgents/com.apple.BezelUIServer.plist"
-#define BEZEL_UI_SERVICE "BezelUI"
-
- if (!(stat(BEZEL_UI_PLIST, &sb) == 0 && S_ISREG(sb.st_mode))) {
- if (bootstrap_create_server(bootstrap_port, BEZEL_UI_PATH, target_user, true, &bezel_ui_server) == BOOTSTRAP_SUCCESS) {
- mach_port_t srv;
-
- if (bootstrap_create_service(bezel_ui_server, BEZEL_UI_SERVICE, &srv) == BOOTSTRAP_SUCCESS) {
- mach_port_deallocate(mach_task_self(), srv);
- }
-
- mach_port_deallocate(mach_task_self(), bezel_ui_server);
- }
- }
-
return 1;
}
+
+
#include <unistd.h>
#include <syslog.h>
#include <pthread.h>
+#include <signal.h>
+#include <assert.h>
+#include <libkern/OSAtomic.h>
+#include <sys/syscall.h>
+
#if HAVE_QUARANTINE
#include <quarantine.h>
#endif
#include "launch.h"
#include "launch_priv.h"
#include "launch_internal.h"
+#include "launchd_ktrace.h"
#include "protocol_vproc.h"
#include "reboot2.h"
+#define likely(x) __builtin_expect((bool)(x), true)
+#define unlikely(x) __builtin_expect((bool)(x), false)
+
static mach_port_t get_root_bootstrap_port(void);
+const char *__crashreporter_info__; /* this should get merged with other versions of the symbol */
+
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;
+
+struct vproc_s {
+ int32_t refcount;
+ mach_port_t j_port;
+};
+
+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 ) {
+ vp = (struct vproc_s *)calloc(1, sizeof(struct vproc_s));
+ if( vp ) {
+ 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);
+ }
+
+ return vp;
+}
+
+vproc_t vproc_retain(vproc_t vp)
+{
+ int32_t orig = OSAtomicAdd32(1, &vp->refcount) - 1;
+ if( orig <= 0 ) {
+ /* 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.";
+ abort();
+ }
+
+ return vp;
+}
+
+void vproc_release(vproc_t vp)
+{
+ int32_t newval = OSAtomicAdd32(-1, &vp->refcount);
+ if( newval < 0 ) {
+ /* We're in negative numbers, which is bad. */
+ __crashreporter_info__ = "Over-release of vproc_t.";
+ abort();
+ } else if( newval == 0 ) {
+ mach_port_deallocate(mach_task_self(), vp->j_port);
+ free(vp);
+ }
+}
+
+static void
+vproc_shmem_init(void)
+{
+ vm_address_t vm_addr = 0;
+ mach_port_t shmem_port;
+ kern_return_t kr;
+
+ kr = vproc_mig_setup_shmem(bootstrap_port, &shmem_port);
+
+ //assert(kr == 0);
+ if (kr) {
+ /* rdar://problem/6416724
+ * If we fail to set up a shared memory page, just allocate a local chunk
+ * of memory. This way, processes can still introspect their own transaction
+ * counts if they're being run under a debugger. Moral of the story: Debug
+ * from the environment you intend to run in.
+ */
+ void *_vm_addr = calloc(1, sizeof(struct vproc_shmem_s));
+ if( !_vm_addr ) {
+ return;
+ }
+
+ vm_addr = (vm_address_t)_vm_addr;
+ } else {
+ kr = vm_map(mach_task_self(), &vm_addr, getpagesize(), 0, true, shmem_port, 0, false,
+ VM_PROT_READ|VM_PROT_WRITE, VM_PROT_READ|VM_PROT_WRITE, VM_INHERIT_NONE);
+
+ //assert(kr == 0);
+ if (kr) return;
+
+ kr = mach_port_deallocate(mach_task_self(), shmem_port);
+
+ //assert(kr == 0);
+ }
+
+ vproc_shmem = (struct vproc_shmem_s *)vm_addr;
+}
+
+static void
+vproc_client_init(void)
+{
+ char *val = getenv(LAUNCHD_DO_APPLE_INTERNAL_LOGGING);
+ if( val ) {
+ if( strncmp(val, "true", sizeof("true") - 1) == 0 ) {
+ do_apple_internal_logging = true;
+ }
+ }
+
+ vproc_shmem_init();
+}
+
+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 */
+#if !TARGET_OS_EMBEDDED
+ _vproc_transaction_begin();
+#endif
+
+ return vpt;
+}
+
+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) {
+ return;
+ }
+ }
+
+ typeof(vproc_shmem->vp_shmem_transaction_cnt) old = 0;
+ do {
+ old = vproc_shmem->vp_shmem_transaction_cnt;
+
+ if (unlikely(old < 0)) {
+ if (vproc_shmem->vp_shmem_flags & VPROC_SHMEM_EXITING) {
+ _exit(0);
+ } else {
+ __crashreporter_info__ = "Unbalanced: vproc_transaction_begin()";
+ }
+ abort();
+ }
+ } 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);
+#endif
+}
+
+size_t
+_vproc_transaction_count(void)
+{
+ return likely(vproc_shmem) ? vproc_shmem->vp_shmem_transaction_cnt : INT32_MAX;
+}
+
+size_t
+_vproc_standby_count(void)
+{
+#ifdef VPROC_STANDBY_IMPLEMENTED
+ return likely(vproc_shmem) ? vproc_shmem->vp_shmem_standby_cnt : INT32_MAX;
+#else
+ return 0;
+#endif
+}
+
+size_t
+_vproc_standby_timeout(void)
+{
+ return likely(vproc_shmem) ? vproc_shmem->vp_shmem_standby_timeout : 0;
+}
+
+bool
+_vproc_pid_is_managed(pid_t p)
+{
+ boolean_t result = false;
+ vproc_mig_pid_is_managed(bootstrap_port, p, &result);
+
+ return result;
+}
+
+kern_return_t
+_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);
+ if( kr == KERN_SUCCESS && condemned ) {
+ *condemned = _condemned ? true : false;
+ }
+
+ return kr;
+}
+
+void
+#if !TARGET_OS_EMBEDDED
+_vproc_transaction_try_exit(int status)
+{
+ if (unlikely(vproc_shmem == NULL)) {
+ return;
+ }
+
+ if (__sync_bool_compare_and_swap(&vproc_shmem->vp_shmem_transaction_cnt, 0, -1)) {
+ vproc_shmem->vp_shmem_flags |= VPROC_SHMEM_EXITING;
+ _exit(status);
+ }
+}
+#else
+_vproc_transaction_try_exit(int status __attribute__((unused)))
+{
+
+}
+#endif
+
+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() ";
+ abort();
+ }
+
+#if !TARGET_OS_EMBEDDED
+ _vproc_transaction_end();
+#endif
+}
+
+void
+_vproc_transaction_end(void)
+{
+#if !TARGET_OS_EMBEDDED
+ typeof(vproc_shmem->vp_shmem_transaction_cnt) newval;
+
+ if (unlikely(vproc_shmem == NULL)) {
+ return;
+ }
+
+ newval = __sync_sub_and_fetch(&vproc_shmem->vp_shmem_transaction_cnt, 1);
+
+ runtime_ktrace(RTKT_VPROC_TRANSACTION_DECREMENT, newval, 0, 0);
+ if (unlikely(newval < 0)) {
+ if (vproc_shmem->vp_shmem_flags & VPROC_SHMEM_EXITING) {
+ _exit(0);
+ } else {
+ __crashreporter_info__ = "Unbalanced: vproc_transaction_end()";
+ }
+ abort();
+ }
+#endif
+}
+
+vproc_standby_t
+vproc_standby_begin(vproc_t vp __attribute__((unused)))
+{
+#ifdef VPROC_STANDBY_IMPLEMENTED
+ vproc_standby_t vpsb = (vproc_standby_t)vproc_shmem_init; /* we need a "random" variable that is testable */
+
+ _vproc_standby_begin();
+
+ return vpsb;
+#else
+ return NULL;
+#endif
+}
+
+void
+_vproc_standby_begin(void)
+{
+#ifdef VPROC_STANDBY_IMPLEMENTED
+ typeof(vproc_shmem->vp_shmem_standby_cnt) newval;
+
+ if (unlikely(vproc_shmem == NULL)) {
+ int po_r = pthread_once(&shmem_inited, vproc_client_init);
+ if (po_r != 0 || vproc_shmem == NULL) {
+ return;
+ }
+ }
+
+ newval = __sync_add_and_fetch(&vproc_shmem->vp_shmem_standby_cnt, 1);
+
+ if (unlikely(newval < 1)) {
+ __crashreporter_info__ = "Unbalanced: vproc_standby_begin()";
+ abort();
+ }
+#else
+ return;
+#endif
+}
+
+void
+vproc_standby_end(vproc_t vp __attribute__((unused)), vproc_standby_t vpt __attribute__((unused)))
+{
+#ifdef VPROC_STANDBY_IMPLEMENTED
+ if (unlikely(vpt != (vproc_standby_t)vproc_shmem_init)) {
+ __crashreporter_info__ = "Bogus standby handle passed to vproc_standby_end() ";
+ abort();
+ }
+
+ _vproc_standby_end();
+#else
+ return;
+#endif
+}
+
+void
+_vproc_standby_end(void)
+{
+#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.";
+ abort();
+ }
+
+ newval = __sync_sub_and_fetch(&vproc_shmem->vp_shmem_standby_cnt, 1);
+
+ if (unlikely(newval < 0)) {
+ __crashreporter_info__ = "Unbalanced: vproc_standby_end()";
+ abort();
+ }
+#else
+ return;
+#endif
+}
kern_return_t
_vproc_grab_subset(mach_port_t bp, mach_port_t *reqport, mach_port_t *rcvright, launch_data_t *outval,
vproc_err_t
_vproc_post_fork_ping(void)
{
- return vproc_mig_post_fork_ping(bootstrap_port, mach_task_self()) == 0 ? NULL : _vproc_post_fork_ping;
-}
-
-static void
-setup_env_hack(const launch_data_t obj, const char *key, void *context __attribute__((unused)))
-{
- setenv(key, launch_data_get_string(obj), 1);
+#if !TARGET_OS_EMBEDDED
+ au_asid_t s = AU_DEFAUDITSID;
+ 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 this happens, our bootstrap port probably got hosed. */
+ _vproc_log(LOG_ERR, "Post-fork ping failed!");
+ break;
+ }
+
+ /* 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 ) {
+ s = ~AU_DEFAUDITSID;
+ break;
+ }
+
+ s = _audit_session_join(session);
+ 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);
+ }
+ } while( 0 );
+
+ return s != AU_DEFAUDITSID ? NULL : _vproc_post_fork_ping;
+#else
+ mach_port_t session = MACH_PORT_NULL;
+ return vproc_mig_post_fork_ping(bootstrap_port, mach_task_self(), &session) ? _vproc_post_fork_ping : NULL;
+#endif
}
vproc_err_t
_vprocmgr_init(const char *session_type)
{
- if (vproc_mig_move_subset(bootstrap_port, MACH_PORT_NULL, (char *)session_type) == 0) {
+ if (vproc_mig_init_session(bootstrap_port, (char *)session_type, _audit_session_self()) == 0) {
return NULL;
}
}
vproc_err_t
-_vprocmgr_move_subset_to_user(uid_t target_user, const char *session_type)
+_vprocmgr_move_subset_to_user(uid_t target_user, const char *session_type, uint64_t flags)
{
- launch_data_t output_obj;
kern_return_t kr = 0;
bool is_bkgd = (strcmp(session_type, VPROCMGR_SESSION_BACKGROUND) == 0);
int64_t ldpid, lduid;
return (vproc_err_t)_vprocmgr_move_subset_to_user;
}
- if (is_bkgd || target_user) {
- mach_port_t puc = 0, rootbs = get_root_bootstrap_port();
-
- if (vproc_mig_lookup_per_user_context(rootbs, target_user, &puc) != 0) {
- return (vproc_err_t)_vprocmgr_move_subset_to_user;
- }
-
- if (is_bkgd) {
- task_set_bootstrap_port(mach_task_self(), puc);
- mach_port_deallocate(mach_task_self(), bootstrap_port);
- bootstrap_port = puc;
- } else {
- kr = vproc_mig_move_subset(puc, bootstrap_port, (char *)session_type);
- mach_port_deallocate(mach_task_self(), puc);
- }
+ mach_port_t puc = 0, rootbs = get_root_bootstrap_port();
+
+ if (vproc_mig_lookup_per_user_context(rootbs, target_user, &puc) != 0) {
+ return (vproc_err_t)_vprocmgr_move_subset_to_user;
+ }
+
+ if( is_bkgd ) {
+ task_set_bootstrap_port(mach_task_self(), puc);
+ mach_port_deallocate(mach_task_self(), bootstrap_port);
+ bootstrap_port = puc;
} else {
- kr = _vprocmgr_init(session_type) ? 1 : 0;
+ kr = vproc_mig_move_subset(puc, bootstrap_port, (char *)session_type, _audit_session_self(), flags);
+ mach_port_deallocate(mach_task_self(), puc);
}
-
+
cached_pid = -1;
if (kr) {
return (vproc_err_t)_vprocmgr_move_subset_to_user;
}
- /* XXX We need to give 'nohup' a better API after Leopard ships */
- if (getprogname() && strcmp(getprogname(), "nohup") != 0) {
- if (vproc_swap_complex(NULL, VPROC_GSK_ENVIRONMENT, NULL, &output_obj) == NULL) {
- if (launch_data_get_type(output_obj) == LAUNCH_DATA_DICTIONARY) {
- launch_data_dict_iterate(output_obj, setup_env_hack, NULL);
- launch_data_free(output_obj);
- }
- }
- }
-
return _vproc_post_fork_ping();
}
+vproc_err_t
+_vprocmgr_switch_to_session(const char *target_session, vproc_flags_t flags __attribute__((unused)))
+{
+ mach_port_t new_bsport = MACH_PORT_NULL;
+ kern_return_t kr = KERN_FAILURE;
+
+ 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 ) {
+ _vproc_log(LOG_NOTICE, "_vprocmgr_switch_to_session(): kr = 0x%x", kr);
+ return (vproc_err_t)_vprocmgr_switch_to_session;
+ }
+
+ task_set_bootstrap_port(mach_task_self(), new_bsport);
+ mach_port_deallocate(mach_task_self(), bootstrap_port);
+ bootstrap_port = new_bsport;
+
+ return !issetugid() ? _vproc_post_fork_ping() : NULL;
+}
+
+vproc_err_t
+_vprocmgr_detach_from_console(vproc_flags_t flags __attribute__((unused)))
+{
+ return _vprocmgr_switch_to_session(VPROCMGR_SESSION_BACKGROUND, 0);
+}
pid_t
_spawn_via_launchd(const char *label, const char *const *argv, const struct spawn_via_launchd_attr *spawn_attrs, int struct_version)
indata = (vm_offset_t)buf;
- kr = vproc_mig_spawn(bootstrap_port, indata, indata_cnt, &p, &obsvr_port);
+ kr = vproc_mig_spawn(bootstrap_port, indata, indata_cnt, _audit_session_self(), &p, &obsvr_port);
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, &p, &obsvr_port);
+ kr = vproc_mig_spawn(puc, indata, indata_cnt, _audit_session_self(), &p, &obsvr_port);
mach_port_deallocate(mach_task_self(), puc);
}
}
}
kern_return_t
-mpm_wait(mach_port_t ajob __attribute__((unused)), int *wstatus)
+mpm_wait(mach_port_t ajob, int *wstatus)
{
return vproc_mig_wait(ajob, wstatus);
}
{
mach_msg_type_number_t outdata_cnt, tmp_cnt;
vm_offset_t outdata = 0;
+ struct timeval tv;
struct logmsg_s *lm;
if (!func) {
}
for (lm = (struct logmsg_s *)outdata; tmp_cnt > 0; lm = ((void *)lm + lm->obj_sz)) {
- lm->from_name += (size_t)lm;
- lm->about_name += (size_t)lm;
- lm->msg += (size_t)lm;
- lm->session_name += (size_t)lm;
+ lm->from_name = (char *)lm + lm->from_name_offset;
+ lm->about_name = (char *)lm + lm->about_name_offset;
+ lm->msg = (char *)lm + lm->msg_offset;
+ lm->session_name = (char *)lm + lm->session_name_offset;
+
+ tv.tv_sec = lm->when / USEC_PER_SEC;
+ tv.tv_usec = lm->when % USEC_PER_SEC;
- func(&lm->when, lm->from_pid, lm->about_pid, lm->sender_uid, lm->sender_gid, lm->pri,
+ func(&tv, lm->from_pid, lm->about_pid, lm->sender_uid, lm->sender_gid, lm->pri,
lm->from_name, lm->about_name, lm->session_name, lm->msg);
tmp_cnt -= lm->obj_sz;
}
vproc_err_t
-vproc_swap_integer(vproc_t vp __attribute__((unused)), vproc_gsk_t key, int64_t *inval, int64_t *outval)
+vproc_swap_integer(vproc_t vp, vproc_gsk_t key, int64_t *inval, int64_t *outval)
{
static int64_t cached_is_managed = -1;
int64_t dummyval = 0;
return NULL;
}
break;
+ case VPROC_GSK_TRANSACTIONS_ENABLED:
+ /* Shared memory region is required for transactions. */
+ if( unlikely(vproc_shmem == NULL) ) {
+ int po_r = pthread_once(&shmem_inited, vproc_client_init);
+ if( po_r != 0 || vproc_shmem == NULL ) {
+ if( outval ) {
+ *outval = -1;
+ }
+ return (vproc_err_t)vproc_swap_integer;
+ }
+ }
+
+ if( s_cached_transactions_enabled && outval ) {
+ *outval = s_cached_transactions_enabled;
+ return NULL;
+ }
+ break;
default:
break;
}
- if (vproc_mig_swap_integer(bootstrap_port, inval ? key : 0, outval ? key : 0, inval ? *inval : 0, outval ? outval : &dummyval) == 0) {
+ kern_return_t kr = KERN_FAILURE;
+ mach_port_t mp = vp ? vp->j_port : bootstrap_port;
+ if ((kr = vproc_mig_swap_integer(mp, inval ? key : 0, outval ? key : 0, inval ? *inval : 0, outval ? outval : &dummyval)) == 0) {
switch (key) {
case VPROC_GSK_MGR_PID:
cached_pid = outval ? *outval : dummyval;
case VPROC_GSK_IS_MANAGED:
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;
+ 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);
+ }
+ break;
+ }
default:
break;
}
}
vproc_err_t
-vproc_swap_complex(vproc_t vp __attribute__((unused)), vproc_gsk_t key, launch_data_t inval, launch_data_t *outval)
+vproc_swap_complex(vproc_t vp, vproc_gsk_t key, launch_data_t inval, launch_data_t *outval)
{
size_t data_offset = 0, good_enough_size = 10*1024*1024;
mach_msg_type_number_t indata_cnt = 0, outdata_cnt;
indata = (vm_offset_t)buf;
}
- if (vproc_mig_swap_complex(bootstrap_port, inval ? key : 0, outval ? key : 0, indata, indata_cnt, &outdata, &outdata_cnt) != 0) {
+ mach_port_t mp = vp ? vp->j_port : bootstrap_port;
+ if (vproc_mig_swap_complex(mp, inval ? key : 0, outval ? key : 0, indata, indata_cnt, &outdata, &outdata_cnt) != 0) {
goto out;
}
return rval;
}
+vproc_err_t
+vproc_swap_string(vproc_t vp, vproc_gsk_t key, const char *instr, char **outstr)
+{
+ launch_data_t instr_data = instr ? launch_data_new_string(instr) : NULL;
+ 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 ) {
+ *outstr = strdup(launch_data_get_string(outstr_data));
+ } else {
+ verr = (vproc_err_t)vproc_swap_string;
+ }
+ launch_data_free(outstr_data);
+ }
+ if( instr_data ) {
+ launch_data_free(instr_data);
+ }
+
+ return verr;
+}
+
void *
reboot2(uint64_t flags)
{
}
vproc_err_t
-_vproc_kickstart_by_label(const char *label, pid_t *out_pid, mach_port_t *out_port_name)
+_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)
{
- if (vproc_mig_embedded_kickstart(bootstrap_port, (char *)label, out_pid, out_port_name) == 0) {
+ 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);
+ }
+
return NULL;
}
--- /dev/null
+/*
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+subsystem job_forward 400;
+
+#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";
+
+userprefix vproc_mig_;
+serverprefix job_mig_;
+
+skip; /* create_server */
+
+skip; /* reboot2 */
+
+skip; /* check_in */
+
+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);
+
+skip; /* send_signal */
+
+simpleroutine parent_forward(
+ __bs_port : job_t;
+replyport __rport : mach_port_move_send_once_t);
+
skip; /* swap_integer */
-skip; /* set_service_policy */
-
skip; /* log */
skip; /* lookup_per_user_context */
simpleroutine job_mig_log_drain_reply(
__r_port : mach_port_move_send_once_t;
__result : kern_return_t, RetCode;
- __outval : pointer_t);
+ __outval : pointer_t);
+
+skip; /* log_forward */
+
+skip; /* kickstart */
+
+skip; /* embedded_wait */
+
+skip; /* lookup_children */
+
+skip; /* switch_to_session */
+
+skip; /* transaction_count_for_pid */
+
+skip; /* pid_is_managed */
+
+skip; /* port_for_label */
+
+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);
type mach_port_move_send_array_t = array[] of mach_port_move_send_t
ctype: mach_port_array_t;
-
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);
+ __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);
+ __bs_port : job_t;
+ __flags : uint64_t);
-routine check_in(
- __bs_port : job_t;
- __service_name : name_t;
- out __service_port : mach_port_move_receive_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);
+ __bs_port : job_t;
+ __service_name : name_t;
+ __service_port : mach_port_t;
+ __flags : uint64_t);
routine look_up2(
- __bs_port : job_t;
- __service_name : name_t;
- out __service_port : mach_port_send_t;
- __target_pid : pid_t;
- __flags : uint64_t);
+ __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);
+ __bs_port : job_t;
+sreplyport __rport : mach_port_make_send_once_t;
+ __label : name_t;
+ __signal : integer_t);
routine parent(
- __bs_port : job_t;
- out __parent_port : mach_port_send_t);
+ __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);
+ __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_active : bootstrap_status_array_t, dealloc);
+ __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);
+ __bs_port : job_t;
+ __requestor_port : mach_port_t;
+out __subset_port : mach_port_make_send_t);
-routine create_service(
- __bs_port : job_t;
- __service_name : name_t;
- out __service_port : mach_port_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);
+ __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);
+ __bs_port : job_t;
+out __sockpath : name_t);
routine spawn(
- __bs_port : job_t;
- __indata : pointer_t;
- out __pid : pid_t;
- out __obsvr_port : mach_port_make_send_t);
+ __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);
+ __bs_port : job_t;
+sreplyport __rport : mach_port_make_send_once_t;
+out __waitval : integer_t);
routine uncork_fork(
- __bs_port : job_t);
+ __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 set_service_policy(
- __bs_port : job_t;
- __target_pid : pid_t;
- __flags : uint64_t;
- __service : name_t);
+ __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);
+ __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);
+ __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);
+ __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);
+ __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);
+ __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);
+ __bs_port : job_t;
+ __inval : pointer_t);
-routine embedded_kickstart(
- __bs_port : job_t;
- __label : name_t;
- out __pid : pid_t;
- out __name_port : mach_port_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);
+ __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 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);
-.Dd May 31, 2006
+.Dd 1 May, 2009
.Dt RC 8
.Os Darwin
.Sh NAME
.Nm rc
.Nm rc.local
.Sh DESCRIPTION
-Prior to Mac OS X 10.5, the
-.Nm rc
-script
-was used to bootstrap the OS. As of Leopard, the system is self-bootstrapped via
-.Xr launchd 8
-which uses the
-.Xr launchctl 1
-bootstrap subcommand to read in launchd jobs from the standard locations.
-For compatibility reasons, the
-.Nm rc.local
-script still continues to work.
-.Pp
-The startup file
.Nm rc.local
-reside in
-.Pa /etc .
+is now unsupported and has been replaced with
+.Xr launchd 8 ,
+which bootstraps itself via the
+.Xr launchctl 1
+.Ar bootstrap
+subcommand to read in
+.Xr launchd 8
+jobs from the standard locations.
.Sh SEE ALSO
.Xr launchd 8 ,
.Xr launchctl 1
#!/bin/sh
##
-# Copyright 2002 Apple Computer, Inc.
+# Copyright 2002-2009 Apple Inc.
#
# This script configures NetBoot
##
return 1
fi
case "${mount_from}" in
- afp:*) fstype=afp;;
+ afp:*)
+ fstype=afp
+ kextutil -v 0 /System/Library/Filesystems/AppleShare/asp_tcp.kext
+ kextutil -v 0 /System/Library/Filesystems/AppleShare/afpfs.kext
+ ;;
nfs:*) fstype=nfs;;
*) echo "unknown network filesystem mount from ${mount_from}"
return 1
;;
esac
- mount -t "${fstype}" "${mount_from}" "${NETBOOT_MOUNT}"
+ mount -t "${fstype}" -o nobrowse "${mount_from}" "${NETBOOT_MOUNT}"
if [ $? -ne 0 ]; then
- echo "mount -t ${fstype} ${mount_from} ${NETBOOT_MOUNT} failed"
+ echo "mount -t ${fstype} -o nobrowse ${mount_from} ${NETBOOT_MOUNT} failed"
return 1
fi
common_start "${NETBOOT_MOUNT}" "${shadow_path}"
__BEGIN_DECLS
+#define RB2_FULLREBOOT 0x8000000000000000llu
+
/* Returns NULL on success. Not NULL on failure */
__attribute__((visibility("default"))) void *reboot2(uint64_t flags);
#include <sys/cdefs.h>
#include <sys/types.h>
+#include <Availability.h>
+
+#ifndef VPROC_HAS_TRANSACTIONS
+ #define VPROC_HAS_TRANSACTIONS
+#endif
__BEGIN_DECLS
typedef void * vproc_err_t;
-typedef void * vproc_t;
+typedef struct vproc_s * vproc_t;
typedef void * vprocmgr_t;
const char *vproc_strerror(vproc_err_t r);
+/*!
+ * @header vproc
+ *
+ * Processes have two reference counts associated with them:
+ *
+ * Transactions Tracks unfinished work. For example: saving a modified
+ * document.
+ * Standby Tracks outstanding callbacks from external subsystems.
+ *
+ * Descriptive aliases:
+ *
+ * A process with no outstanding transactions is called "clean."
+ * A process with outstanding transactions is called "dirty."
+ * A process with no standby work is called "idle."
+ *
+ * Sometimes, the operating system needs processes to exit. Unix has two
+ * primary signals to kill applications:
+ *
+ * SIGKILL Not catchable by the application.
+ * SIGTERM Catchable by the application.
+ *
+ * If a process is clean, the operating system is free to SIGKILL it at
+ * shutdown or logout. This behavior is opt in.
+ *
+ * If a process is clean and idle, the operating system may send SIGKILL after
+ * a application specified timeout. This behavior is opt in.
+ *
+ * If a process is dirty and idle, the operating system may send SIGTERM after
+ * a application specified timeout. This behavior is opt in.
+ *
+ *
+ * launchd jobs should update their property lists accordingly.
+ *
+ * We plan to have LaunchServices use private methods to coordinate
+ * whether GUI applications have opted into this design.
+ */
+
+/*!
+ * @typedef vproc_transaction_t
+ *
+ * @abstract
+ * An opaque handle used to track outstanding transactions.
+ */
+typedef struct vproc_transaction_s *vproc_transaction_t;
+
+/*!
+ * @function vproc_transaction_begin
+ *
+ * @param virtual_proc
+ * This is meant for future API improvements. Pass NULL for now.
+ *
+ * @result
+ * Returns an opaque handle to be passed to vproc_transaction_end().
+ *
+ * @abstract
+ * 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);
+
+/*!
+ * @function vproc_transaction_end
+ *
+ * @param virtual_proc
+ * This is meant for future API improvements. Pass NULL for now.
+ *
+ * @param handle
+ * The handle previously created with vproc_transaction_begin().
+ *
+ * @abstract
+ * Call this API after the data has either been flushed or otherwise resolved.
+ *
+ * @discussion
+ * 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);
+
+/*!
+ * @typedef vproc_standby_t
+ *
+ * @abstract
+ * An opaque handle used to track outstanding standby requests.
+ */
+typedef struct vproc_standby_s *vproc_standby_t;
+
+/*!
+ * @function vproc_standby_begin
+ *
+ * @param virtual_proc
+ * This is meant for future API improvements. Pass NULL for now.
+ *
+ * @result
+ * Returns an opaque handle to be passed to vproc_standby_end().
+ *
+ * @abstract
+ * Call this API before registering notifications. For example: timers network
+ * state change, or when monitoring keyboard/mouse events.
+ *
+ * @discussion
+ * This API is undefined and is currently a no-op.
+ */
+vproc_standby_t
+vproc_standby_begin(vproc_t virtual_proc) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_NA);
+
+/*!
+ * @function vproc_standby_end
+ *
+ * @param virtual_proc
+ * This is meant for future API improvements. Pass NULL for now.
+ *
+ * @param handle
+ * The handle previously created with vproc_standby_begin().
+ *
+ * @abstract
+ * Call this API when deregistering notifications.
+ *
+ * @discussion
+ * Calling this API with the same handle more than once is undefined.
+ * This API is undefined and is currently a no-op.
+ */
+void
+vproc_standby_end(vproc_t virtual_proc, vproc_standby_t handle) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_NA);
+
#pragma GCC visibility pop
__END_DECLS
#include <sys/queue.h>
#include <sys/time.h>
#include <stdarg.h>
+#include <sys/syscall.h>
+#include <bsm/audit.h>
#include "launch.h"
#include "bootstrap.h"
#include "vproc.h"
typedef pid_t * pid_array_t;
typedef mach_port_t vproc_mig_t;
+#define VPROC_SHMEM_EXITING 0x1
+
+struct vproc_shmem_s {
+ int32_t vp_shmem_transaction_cnt;
+ int32_t vp_shmem_standby_cnt;
+ uint32_t vp_shmem_standby_timeout;
+ int32_t vp_shmem_flags;
+};
+
#ifdef protocol_vproc_MSG_COUNT
/* HACK */
#include "launchd_core_logic.h"
vproc_err_t _vprocmgr_init(const char *session_type);
vproc_err_t _vproc_post_fork_ping(void);
+#if !TARGET_OS_EMBEDDED
+ #define _audit_session_self(v) (mach_port_t)syscall(SYS_audit_session_self)
+ #define _audit_session_join(s) (au_asid_t)syscall(SYS_audit_session_join, session)
+#else
+ #define _audit_session_self(v) MACH_PORT_NULL
+ #define _audit_session_join(s) 0
+#endif
+
#define SPAWN_HAS_PATH 0x0001
#define SPAWN_HAS_WDIR 0x0002
#define SPAWN_HAS_UMASK 0x0004
kern_return_t _vprocmgr_getsocket(name_t);
-
struct logmsg_s {
- STAILQ_ENTRY(logmsg_s) sqe;
- struct timeval when;
+ union {
+ STAILQ_ENTRY(logmsg_s) sqe;
+ uint64_t __pad;
+ };
+ int64_t when;
pid_t from_pid;
pid_t about_pid;
uid_t sender_uid;
gid_t sender_gid;
int err_num;
int pri;
- const char *from_name;
- const char *about_name;
- const char *session_name;
- const char *msg;
- size_t obj_sz;
+ union {
+ const char *from_name;
+ uint64_t from_name_offset;
+ };
+ union {
+ const char *about_name;
+ uint64_t about_name_offset;
+ };
+ union {
+ const char *session_name;
+ uint64_t session_name_offset;
+ };
+ union {
+ const char *msg;
+ uint64_t msg_offset;
+ };
+ uint64_t obj_sz;
char data[0];
};
-void _vproc_logv(int pri, int err, const char *msg, va_list ap);
vproc_err_t _vprocmgr_log_forward(mach_port_t mp, void *data, size_t len);
kern_return_t
-bootstrap_info(
- mach_port_t bp,
- name_array_t *service_names,
- mach_msg_type_number_t *service_namesCnt,
- bootstrap_status_array_t *service_active,
- mach_msg_type_number_t *service_activeCnt);
+bootstrap_info(mach_port_t bp,
+ name_array_t *service_names,
+ mach_msg_type_number_t *service_namesCnt,
+ name_array_t *service_jobs,
+ mach_msg_type_number_t *service_jobsCnt,
+ bootstrap_status_array_t *service_active,
+ mach_msg_type_number_t *service_activeCnt,
+ uint64_t flags);
#pragma GCC visibility pop
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
+#include <Availability.h>
#include <sys/types.h>
#include <sys/cdefs.h>
#include <sys/syslog.h>
#include <sys/time.h>
#include <stdbool.h>
#include <launch.h>
+#include <vproc.h>
+#include <uuid/uuid.h>
+
+#ifndef VPROC_HAS_TRANSACTIONS
+ #define VPROC_HAS_TRANSACTIONS
+#endif
__BEGIN_DECLS
#pragma GCC visibility push(default)
-/* DO NOT use this. This is a hack for launchctl */
-#define VPROC_MAGIC_UNLOAD_SIGNAL 0x4141504C
+/* DO NOT use this. This is a hack for 'launchctl' */
+#define VPROC_MAGIC_UNLOAD_SIGNAL 0x4141504C
+/* DO NOT use this. This is a hack for 'loginwindow' */
+#define VPROC_MAGIC_TRYKILL_SIGNAL 0x6161706C
typedef enum {
VPROC_GSK_LAST_EXIT_STATUS = 1,
VPROC_GSK_MGR_UID,
VPROC_GSK_MGR_PID,
VPROC_GSK_IS_MANAGED,
+ VPROC_GSK_MGR_NAME,
VPROC_GSK_BASIC_KEEPALIVE,
VPROC_GSK_START_INTERVAL,
VPROC_GSK_IDLE_TIMEOUT,
VPROC_GSK_ALLJOBS,
VPROC_GSK_GLOBAL_LOG_MASK,
VPROC_GSK_GLOBAL_UMASK,
+ VPROC_GSK_ABANDON_PROCESS_GROUP,
+ VPROC_GSK_TRANSACTIONS_ENABLED,
+ VPROC_GSK_WEIRD_BOOTSTRAP,
+ VPROC_GSK_WAITFORDEBUGGER,
+ VPROC_GSK_SECURITYSESSION,
+ VPROC_GSK_SHUTDOWN_DEBUGGING,
+ VPROC_GSK_VERBOSE_BOOT,
+ VPROC_GSK_PERUSER_SUSPEND,
+ VPROC_GSK_PERUSER_RESUME,
+ VPROC_GSK_JOB_OVERRIDES_DB,
+ VPROC_GSK_JOB_CACHE_DB,
+ VPROC_GSK_EMBEDDEDROOTEQUIVALENT,
} vproc_gsk_t;
+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
+
+vproc_t vprocmgr_lookup_vproc(const char *label);
+vproc_t vproc_retain(vproc_t vp);
+void vproc_release(vproc_t vp);
+
vproc_err_t vproc_swap_integer(vproc_t vp, vproc_gsk_t key, int64_t *inval, int64_t *outval);
vproc_err_t vproc_swap_complex(vproc_t vp, vproc_gsk_t key, launch_data_t inval, launch_data_t *outval);
+vproc_err_t vproc_swap_string(vproc_t vp, vproc_gsk_t key, const char *instr, char **outstr);
vproc_err_t _vproc_get_last_exit_status(int *wstatus);
vproc_err_t _vproc_set_global_on_demand(bool val);
vproc_err_t _vprocmgr_log_drain(vproc_t vp, pthread_mutex_t *optional_mutex_around_callback, _vprocmgr_log_drain_callback_t func);
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);
+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_logv(int pri, int err, const char *msg, va_list ap) __attribute__((format(printf, 3, 0)));
#define VPROCMGR_SESSION_LOGINWINDOW "LoginWindow"
-#define VPROCMGR_SESSION_BACKGROUND "Background"
-#define VPROCMGR_SESSION_AQUA "Aqua"
-#define VPROCMGR_SESSION_STANDARDIO "StandardIO"
-#define VPROCMGR_SESSION_SYSTEM "System"
-
-vproc_err_t _vprocmgr_move_subset_to_user(uid_t target_user, const char *session_type);
+#define VPROCMGR_SESSION_BACKGROUND "Background"
+#define VPROCMGR_SESSION_AQUA "Aqua"
+#define VPROCMGR_SESSION_STANDARDIO "StandardIO"
+#define VPROCMGR_SESSION_SYSTEM "System"
+
+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);
#pragma GCC visibility pop
--- /dev/null
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+int
+main(void)
+{
+ int wstatus;
+ pid_t p, wr;
+ int kill_r, killpg_r, r;
+ int kill_e, killpg_e;
+
+ p = fork();
+ assert(p != -1);
+
+ if (p == 0) {
+ r = setsid();
+ assert(r != -1);
+ _exit(EXIT_SUCCESS);
+ }
+
+ sleep(1);
+
+ errno = 0;
+ kill_r = kill(p, SIGTERM);
+ kill_e = errno;
+
+ errno = 0;
+ killpg_r = kill(-(p), SIGTERM);
+ killpg_e = errno;
+
+ if (kill_r != killpg_r) {
+ fprintf(stderr, "Bug. kill() is inconsistent.\n");
+ fprintf(stderr, "kill( p, SIGTERM) returned %d and errno == %d\n", kill_r, kill_e);
+ fprintf(stderr, "kill(-(p), SIGTERM) returned %d and errno == %d\n", killpg_r, killpg_e);
+ if (kill_e == EPERM || killpg_e == EPERM) {
+ fprintf(stderr, "The kernel lied. We should have the right to kill 'p' and it returned EPERM.\n");
+ }
+ if (kill_e == ESRCH || killpg_e == ESRCH) {
+ fprintf(stderr, "The kernel is confused. PID 'p' exists, but the kernel couldn't find it.\n");
+ }
+
+ exit(EXIT_FAILURE);
+ }
+
+ wr = waitpid(p, &wstatus, 0);
+ assert(wr == p);
+
+ exit(EXIT_SUCCESS);
+}