mirror of
https://github.com/darlinghq/darling-Libnotify.git
synced 2024-11-26 21:50:29 +00:00
Update Source To Libnotify-279.40.4
This commit is contained in:
parent
4fd1e8f5ff
commit
c8f232db15
@ -34,6 +34,7 @@
|
||||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1864C88E23F227D200A383C1 /* notify_test_helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 1864C88223F2174E00A383C1 /* notify_test_helper.c */; };
|
||||
1886391920E1A2BF00C8BEA9 /* notify_bench.c in Sources */ = {isa = PBXBuildFile; fileRef = 727C90371B9A372700D5B754 /* notify_bench.c */; };
|
||||
2D312B76102CA2E300F90022 /* libnotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D312B73102CA2E300F90022 /* libnotify.c */; };
|
||||
2D312B77102CA2E300F90022 /* notify_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D312B74102CA2E300F90022 /* notify_client.c */; };
|
||||
@ -60,7 +61,6 @@
|
||||
3FA21AD0148AAA5000099D2F /* notifyd.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FA21A9E148AA7FA00099D2F /* notifyd.c */; };
|
||||
3FA21AD1148AAA5000099D2F /* pathwatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FA21AA0148AA7FA00099D2F /* pathwatch.c */; };
|
||||
3FA21AD2148AAA5000099D2F /* service.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FA21AA2148AA7FA00099D2F /* service.c */; };
|
||||
3FA21AD3148AAA5000099D2F /* timer.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FA21AA5148AA7FA00099D2F /* timer.c */; };
|
||||
3FA21AD4148AAA5D00099D2F /* notifyd.8 in Install man page */ = {isa = PBXBuildFile; fileRef = 3FA21A9D148AA7FA00099D2F /* notifyd.8 */; };
|
||||
3FA21AD5148AAA6E00099D2F /* notifyutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FA21AA9148AA82700099D2F /* notifyutil.c */; };
|
||||
3FA21AD6148AAA7500099D2F /* notifyutil.1 in Install man page */ = {isa = PBXBuildFile; fileRef = 3FA21AA8148AA82700099D2F /* notifyutil.1 */; };
|
||||
@ -81,6 +81,13 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
1864C88C23F227C200A383C1 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 1864C88323F227AC00A383C1;
|
||||
remoteInfo = notfity_test_helper;
|
||||
};
|
||||
3FA21ACA148AA94A00099D2F /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
|
||||
@ -185,14 +192,20 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
180F8D3E21136EBF009A472B /* notify_pathwatch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = notify_pathwatch.c; sourceTree = "<group>"; };
|
||||
18177A7123612EDC008CCFDE /* notify_register_mach_port.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = notify_register_mach_port.c; sourceTree = "<group>"; };
|
||||
182FD2C2210BB0F600BF263C /* notify_benchmark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_benchmark.c; sourceTree = "<group>"; };
|
||||
18314CC821FF867600FEB43D /* notifyutil_entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = notifyutil_entitlements.plist; sourceTree = "<group>"; };
|
||||
18383C6720F909A300D5C465 /* notify_regenerate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_regenerate.c; sourceTree = "<group>"; };
|
||||
18383C6820F909A300D5C465 /* notify_register_signal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_register_signal.c; sourceTree = "<group>"; };
|
||||
18383C6920F909A300D5C465 /* notify_sigusr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_sigusr.c; sourceTree = "<group>"; };
|
||||
183F91E32357FCEB009A1BFC /* notify_suspend.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = notify_suspend.c; sourceTree = "<group>"; };
|
||||
1846D85A24AAC578001D052D /* notify_register_file_desc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = notify_register_file_desc.c; sourceTree = "<group>"; };
|
||||
1864C88123F216CB00A383C1 /* notify_exec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_exec.c; sourceTree = "<group>"; };
|
||||
1864C88223F2174E00A383C1 /* notify_test_helper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = notify_test_helper.c; sourceTree = "<group>"; };
|
||||
1864C88B23F227AC00A383C1 /* notify_test_helper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = notify_test_helper; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
1886391720E1A22F00C8BEA9 /* notifybench */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = notifybench; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2D312B73102CA2E300F90022 /* libnotify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libnotify.c; sourceTree = "<group>"; usesTabs = 1; };
|
||||
2D312B74102CA2E300F90022 /* notify_client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_client.c; sourceTree = "<group>"; usesTabs = 1; };
|
||||
2D312B74102CA2E300F90022 /* notify_client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_client.c; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
|
||||
2D312B75102CA2E300F90022 /* table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = table.c; sourceTree = "<group>"; };
|
||||
2D312B79102CA30200F90022 /* notify_ipc.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = notify_ipc.defs; sourceTree = "<group>"; };
|
||||
2D312B7C102CA32500F90022 /* notify_keys.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; path = notify_keys.h; sourceTree = "<group>"; };
|
||||
@ -217,7 +230,6 @@
|
||||
3F82235D12B18551005DD509 /* libnotify.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = libnotify.xcconfig; sourceTree = "<group>"; };
|
||||
3F8223B412B18877005DD509 /* libsystem_notify.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_notify.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3F947780191C322100A93E8E /* no-sim-man.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "no-sim-man.sh"; sourceTree = "<group>"; };
|
||||
3F947781191C322100A93E8E /* sim-compat-symlink.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "sim-compat-symlink.sh"; sourceTree = "<group>"; };
|
||||
3F999961185C474E00EAD3A0 /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = "<group>"; };
|
||||
3F999963185C474E00EAD3A0 /* notifyd.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = notifyd.xcconfig; sourceTree = "<group>"; };
|
||||
3F999964185C474E00EAD3A0 /* notifyutil.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = notifyutil.xcconfig; sourceTree = "<group>"; };
|
||||
@ -232,8 +244,6 @@
|
||||
3FA21AA1148AA7FA00099D2F /* pathwatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathwatch.h; sourceTree = "<group>"; };
|
||||
3FA21AA2148AA7FA00099D2F /* service.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = service.c; sourceTree = "<group>"; usesTabs = 1; };
|
||||
3FA21AA3148AA7FA00099D2F /* service.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = service.h; sourceTree = "<group>"; };
|
||||
3FA21AA5148AA7FA00099D2F /* timer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = timer.c; sourceTree = "<group>"; };
|
||||
3FA21AA6148AA7FA00099D2F /* timer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = timer.h; sourceTree = "<group>"; };
|
||||
3FA21AA8148AA82700099D2F /* notifyutil.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = notifyutil.1; sourceTree = "<group>"; };
|
||||
3FA21AA9148AA82700099D2F /* notifyutil.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = notifyutil.c; sourceTree = "<group>"; };
|
||||
3FA21AB0148AA8E300099D2F /* notifyd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = notifyd; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@ -252,11 +262,14 @@
|
||||
727C90391B9A372700D5B754 /* notify_disable_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_disable_test.c; sourceTree = "<group>"; };
|
||||
727C903A1B9A372700D5B754 /* notify_many_dups.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_many_dups.c; sourceTree = "<group>"; };
|
||||
727C903B1B9A372700D5B754 /* random_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = random_test.c; sourceTree = "<group>"; };
|
||||
7875226923A34F3B002B6F1D /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = "<group>"; };
|
||||
94099C732087E7D50004B6BC /* xctests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = xctests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
94099C752087E7D50004B6BC /* RegisterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RegisterTests.m; sourceTree = "<group>"; };
|
||||
94099C772087E7D50004B6BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
9487BF2820882DAD0043BF74 /* parallel_register_cancel.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = parallel_register_cancel.c; sourceTree = "<group>"; };
|
||||
9B71D22F206AB52200BB9574 /* notify_qos.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_qos.c; sourceTree = "<group>"; };
|
||||
C0FF3C23234516ED00ABBA89 /* notify_matching.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_matching.c; sourceTree = "<group>"; };
|
||||
C0FF3C242345172700ABBA89 /* notify_leaks.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = notify_leaks.c; sourceTree = "<group>"; };
|
||||
E6481E7E2165785F00C04412 /* notify_probes.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; path = notify_probes.d; sourceTree = "<group>"; };
|
||||
FC7B7A52155781930064D203 /* notify_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = notify_internal.h; sourceTree = "<group>"; usesTabs = 1; };
|
||||
/* End PBXFileReference section */
|
||||
@ -320,6 +333,7 @@
|
||||
94099C732087E7D50004B6BC /* xctests.xctest */,
|
||||
1886391720E1A22F00C8BEA9 /* notifybench */,
|
||||
6EC91ED32178FF7100F11587 /* Frameworks */,
|
||||
1864C88B23F227AC00A383C1 /* notify_test_helper */,
|
||||
);
|
||||
name = Libnotify;
|
||||
sourceTree = "<group>";
|
||||
@ -383,7 +397,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3F947780191C322100A93E8E /* no-sim-man.sh */,
|
||||
3F947781191C322100A93E8E /* sim-compat-symlink.sh */,
|
||||
);
|
||||
path = xcodescripts;
|
||||
sourceTree = "<group>";
|
||||
@ -415,12 +428,13 @@
|
||||
3FA21A98148AA7FA00099D2F /* notifyd */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7875226923A34F3B002B6F1D /* entitlements.plist */,
|
||||
2DD962061B14E6560040D341 /* com.apple.notifyd.sb */,
|
||||
3FA21ADC148AABA900099D2F /* Build Support */,
|
||||
3FA21A99148AA7FA00099D2F /* com.apple.notifyd.plist */,
|
||||
3FA21A9A148AA7FA00099D2F /* notify.conf */,
|
||||
3FA21AAA148AA85300099D2F /* Source */,
|
||||
3FA21A9D148AA7FA00099D2F /* notifyd.8 */,
|
||||
3FA21ADC148AABA900099D2F /* Build Support */,
|
||||
3FA21AAA148AA85300099D2F /* Source */,
|
||||
3FA21AAB148AA86600099D2F /* Private Headers */,
|
||||
);
|
||||
path = notifyd;
|
||||
@ -443,7 +457,6 @@
|
||||
3FA21A9E148AA7FA00099D2F /* notifyd.c */,
|
||||
3FA21AA0148AA7FA00099D2F /* pathwatch.c */,
|
||||
3FA21AA2148AA7FA00099D2F /* service.c */,
|
||||
3FA21AA5148AA7FA00099D2F /* timer.c */,
|
||||
);
|
||||
name = Source;
|
||||
sourceTree = "<group>";
|
||||
@ -454,7 +467,6 @@
|
||||
3FA21A9F148AA7FA00099D2F /* notifyd.h */,
|
||||
3FA21AA1148AA7FA00099D2F /* pathwatch.h */,
|
||||
3FA21AA3148AA7FA00099D2F /* service.h */,
|
||||
3FA21AA6148AA7FA00099D2F /* timer.h */,
|
||||
);
|
||||
name = "Private Headers";
|
||||
sourceTree = "<group>";
|
||||
@ -492,7 +504,12 @@
|
||||
727C902F1B9A372700D5B754 /* tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1864C88123F216CB00A383C1 /* notify_exec.c */,
|
||||
1864C88223F2174E00A383C1 /* notify_test_helper.c */,
|
||||
C0FF3C23234516ED00ABBA89 /* notify_matching.c */,
|
||||
18383C6720F909A300D5C465 /* notify_regenerate.c */,
|
||||
1846D85A24AAC578001D052D /* notify_register_file_desc.c */,
|
||||
18177A7123612EDC008CCFDE /* notify_register_mach_port.c */,
|
||||
18383C6820F909A300D5C465 /* notify_register_signal.c */,
|
||||
18383C6920F909A300D5C465 /* notify_sigusr.c */,
|
||||
727C90341B9A372700D5B754 /* Makefile */,
|
||||
@ -501,10 +518,12 @@
|
||||
727C90381B9A372700D5B754 /* notify_control.c */,
|
||||
727C90391B9A372700D5B754 /* notify_disable_test.c */,
|
||||
727C903A1B9A372700D5B754 /* notify_many_dups.c */,
|
||||
183F91E32357FCEB009A1BFC /* notify_suspend.c */,
|
||||
727C903B1B9A372700D5B754 /* random_test.c */,
|
||||
9487BF2820882DAD0043BF74 /* parallel_register_cancel.c */,
|
||||
182FD2C2210BB0F600BF263C /* notify_benchmark.c */,
|
||||
180F8D3E21136EBF009A472B /* notify_pathwatch.c */,
|
||||
C0FF3C242345172700ABBA89 /* notify_leaks.c */,
|
||||
);
|
||||
path = tests;
|
||||
sourceTree = "<group>";
|
||||
@ -564,6 +583,7 @@
|
||||
buildToolPath = /usr/bin/make;
|
||||
buildWorkingDirectory = tests;
|
||||
dependencies = (
|
||||
1864C88D23F227C200A383C1 /* PBXTargetDependency */,
|
||||
);
|
||||
name = darwintests;
|
||||
passBuildSettingsInEnvironment = 1;
|
||||
@ -572,6 +592,21 @@
|
||||
/* End PBXLegacyTarget section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
1864C88323F227AC00A383C1 /* notify_test_helper */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1864C88823F227AC00A383C1 /* Build configuration list for PBXNativeTarget "notify_test_helper" */;
|
||||
buildPhases = (
|
||||
1864C88423F227AC00A383C1 /* Sources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = notify_test_helper;
|
||||
productName = notifyutil;
|
||||
productReference = 1864C88B23F227AC00A383C1 /* notify_test_helper */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
1886390E20E1A22F00C8BEA9 /* notifybench */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1886391420E1A22F00C8BEA9 /* Build configuration list for PBXNativeTarget "notifybench" */;
|
||||
@ -652,7 +687,6 @@
|
||||
D289987405E68DCB004EDB86 /* Frameworks */,
|
||||
2D38AA09102CD87C00D3D622 /* Copy man3 Files */,
|
||||
3F947782191C324900A93E8E /* No Simulator Man Pages */,
|
||||
3F947783191C327700A93E8E /* Sim compat symlink */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -669,6 +703,7 @@
|
||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1100;
|
||||
TargetAttributes = {
|
||||
72FA84F61BD6E9DF00A4CC6F = {
|
||||
CreatedOnToolsVersion = 7.1;
|
||||
@ -683,13 +718,10 @@
|
||||
};
|
||||
buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "Libnotify" */;
|
||||
compatibilityVersion = "Xcode 3.1";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
English,
|
||||
Japanese,
|
||||
French,
|
||||
German,
|
||||
en,
|
||||
);
|
||||
mainGroup = 08FB7794FE84155DC02AAC07 /* Libnotify */;
|
||||
productRefGroup = 08FB7794FE84155DC02AAC07 /* Libnotify */;
|
||||
@ -700,6 +732,7 @@
|
||||
3FA21AAF148AA8E300099D2F /* notifyd */,
|
||||
3FA21ABD148AA8F000099D2F /* notifyutil */,
|
||||
1886390E20E1A22F00C8BEA9 /* notifybench */,
|
||||
1864C88323F227AC00A383C1 /* notify_test_helper */,
|
||||
3FA21AC7148AA93000099D2F /* cli_apps */,
|
||||
72FA84F61BD6E9DF00A4CC6F /* darwintests */,
|
||||
72FA84FB1BD6EAB900A4CC6F /* tests */,
|
||||
@ -734,21 +767,6 @@
|
||||
shellPath = "/bin/bash -e -x";
|
||||
shellScript = "exec \"${SCRIPT_INPUT_FILE_0}\"";
|
||||
};
|
||||
3F947783191C327700A93E8E /* Sim compat symlink */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 8;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(SRCROOT)/xcodescripts/sim-compat-symlink.sh",
|
||||
);
|
||||
name = "Sim compat symlink";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
shellPath = "/bin/bash -e -x";
|
||||
shellScript = "exec \"${SCRIPT_INPUT_FILE_0}\"";
|
||||
};
|
||||
3F947784191C32DC00A93E8E /* No Simulator Man Pages */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 8;
|
||||
@ -782,6 +800,14 @@
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
1864C88423F227AC00A383C1 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1864C88E23F227D200A383C1 /* notify_test_helper.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
1886390F20E1A22F00C8BEA9 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -802,7 +828,6 @@
|
||||
9456B8522023CAB300CF7D27 /* libnotify.c in Sources */,
|
||||
3FA21AD1148AAA5000099D2F /* pathwatch.c in Sources */,
|
||||
3FA21AD2148AAA5000099D2F /* service.c in Sources */,
|
||||
3FA21AD3148AAA5000099D2F /* timer.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -841,6 +866,11 @@
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
1864C88D23F227C200A383C1 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 1864C88323F227AC00A383C1 /* notify_test_helper */;
|
||||
targetProxy = 1864C88C23F227C200A383C1 /* PBXContainerItemProxy */;
|
||||
};
|
||||
3FA21ACB148AA94A00099D2F /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 3FA21AAF148AA8E300099D2F /* notifyd */;
|
||||
@ -859,10 +889,31 @@
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
1864C88923F227AC00A383C1 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F999964185C474E00EAD3A0 /* notifyutil.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
INSTALL_PATH = /AppleInternal/Tests/Libnotify/;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
1864C88A23F227AC00A383C1 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F999964185C474E00EAD3A0 /* notifyutil.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
INSTALL_PATH = /AppleInternal/Tests/Libnotify/;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1886391520E1A22F00C8BEA9 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F999964185C474E00EAD3A0 /* notifyutil.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
INSTALL_PATH = /usr/local/bin;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
@ -872,6 +923,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F999964185C474E00EAD3A0 /* notifyutil.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
INSTALL_PATH = /usr/local/bin;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
@ -881,6 +933,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F82235D12B18551005DD509 /* libnotify.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -888,18 +941,41 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLY_RULES_IN_COPY_FILES = "";
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
LLVM_LTO = YES;
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
SUPPORTED_PLATFORMS = "watchsimulator watchos iphonesimulator iphoneos macosx bridgeos appletvsimulator appletvos";
|
||||
WARNING_CFLAGS = "-Wno-dollar-in-identifier-extension";
|
||||
};
|
||||
@ -909,6 +985,8 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F999963185C474E00EAD3A0 /* notifyd.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = notifyd/entitlements.plist;
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DSINGLE_THREADED_NOTIFY_STATE=1",
|
||||
@ -921,6 +999,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F999964185C474E00EAD3A0 /* notifyutil.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = notifyutil/notifyutil_entitlements.plist;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
@ -930,6 +1009,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F999961185C474E00EAD3A0 /* base.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
@ -937,6 +1017,7 @@
|
||||
72FA84F81BD6E9DF00A4CC6F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COPY_PHASE_STRIP = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx.internal;
|
||||
@ -947,6 +1028,7 @@
|
||||
72FA84FD1BD6EAB900A4CC6F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "macosx iphoneos watchos appletvos";
|
||||
};
|
||||
@ -1017,18 +1099,43 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLY_RULES_IN_COPY_FILES = "";
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
LLVM_LTO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
SUPPORTED_PLATFORMS = "watchsimulator watchos iphonesimulator iphoneos macosx bridgeos appletvsimulator appletvos";
|
||||
WARNING_CFLAGS = "-Wno-dollar-in-identifier-extension";
|
||||
};
|
||||
@ -1038,6 +1145,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F82235D12B18551005DD509 /* libnotify.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -1045,6 +1153,8 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F999963185C474E00EAD3A0 /* notifyd.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = notifyd/entitlements.plist;
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DSINGLE_THREADED_NOTIFY_STATE=1",
|
||||
@ -1057,6 +1167,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F999964185C474E00EAD3A0 /* notifyutil.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = notifyutil/notifyutil_entitlements.plist;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
@ -1066,6 +1177,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3F999961185C474E00EAD3A0 /* base.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
@ -1073,6 +1185,7 @@
|
||||
949B7842208BE1F2002AD6AF /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COPY_PHASE_STRIP = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx.internal;
|
||||
@ -1083,6 +1196,7 @@
|
||||
949B7843208BE1F2002AD6AF /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "macosx iphoneos watchos appletvos";
|
||||
};
|
||||
@ -1154,6 +1268,15 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
1864C88823F227AC00A383C1 /* Build configuration list for PBXNativeTarget "notify_test_helper" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1864C88923F227AC00A383C1 /* Release */,
|
||||
1864C88A23F227AC00A383C1 /* Debug */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
1886391420E1A22F00C8BEA9 /* Build configuration list for PBXNativeTarget "notifybench" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1000"
|
||||
LastUpgradeVersion = "1100"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@ -39,8 +39,6 @@
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@ -52,8 +50,6 @@
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
237
libnotify.c
237
libnotify.c
@ -145,6 +145,7 @@ _notify_lib_notify_state_init(notify_state_t * ns, uint32_t flags)
|
||||
_nc_table_init_64(&ns->client_table, offsetof(client_t, cid.hash_key));
|
||||
_nc_table_init_n(&ns->port_table, offsetof(port_data_t, port));
|
||||
_nc_table_init_n(&ns->proc_table, offsetof(proc_data_t, pid));
|
||||
_nc_table_init_64(&ns->event_table, offsetof(event_data_t, event_token));
|
||||
}
|
||||
|
||||
// We only need to lock in the client
|
||||
@ -170,6 +171,8 @@ _internal_client_new(notify_state_t *ns, pid_t pid, int token, name_info_t *n)
|
||||
client_t *c;
|
||||
uint64_t cid = make_client_id(pid, token);
|
||||
|
||||
n->refcount++;
|
||||
|
||||
/* detect duplicates - should never happen, but it would be bad */
|
||||
c = _nc_table_find_64(&ns->client_table, cid);
|
||||
if (c != NULL) return NULL;
|
||||
@ -182,7 +185,6 @@ _internal_client_new(notify_state_t *ns, pid_t pid, int token, name_info_t *n)
|
||||
c->name_info = n;
|
||||
|
||||
LIST_INSERT_HEAD(&n->subscriptions, c, client_subscription_entry);
|
||||
n->refcount++;
|
||||
|
||||
_nc_table_insert_64(&ns->client_table, &c->cid.hash_key);
|
||||
return c;
|
||||
@ -193,9 +195,9 @@ _internal_client_release(notify_state_t *ns, client_t *c)
|
||||
{
|
||||
_nc_table_delete_64(&ns->client_table, c->cid.hash_key);
|
||||
|
||||
if (c->state_and_type & NOTIFY_TYPE_FILE) {
|
||||
if (notify_is_type(c->state_and_type, NOTIFY_TYPE_FILE)) {
|
||||
if (c->deliver.fd >= 0) close(c->deliver.fd);
|
||||
} else if (c->state_and_type & NOTIFY_TYPE_PORT) {
|
||||
} else if (notify_is_type(c->state_and_type, NOTIFY_TYPE_PORT)) {
|
||||
/* release my send right to the port */
|
||||
mach_port_deallocate(mach_task_self(), c->deliver.port);
|
||||
}
|
||||
@ -238,7 +240,7 @@ _internal_new_name(notify_state_t *ns, const char *name)
|
||||
static void
|
||||
_internal_insert_controlled_name(notify_state_t *ns, name_info_t *n)
|
||||
{
|
||||
int i, j;
|
||||
uint32_t i, j;
|
||||
|
||||
if (n == NULL) return;
|
||||
|
||||
@ -361,6 +363,72 @@ _notify_lib_check_controlled_access(notify_state_t *ns, char *name, uid_t uid, g
|
||||
return status;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
_internal_send_port(notify_state_t *ns, client_t *c, port_data_t *port_data, mach_port_t port)
|
||||
{
|
||||
kern_return_t kstatus;
|
||||
mach_msg_empty_send_t msg;
|
||||
mach_msg_option_t opts = MACH_SEND_MSG | MACH_SEND_TIMEOUT;
|
||||
|
||||
if (port_data == NULL)
|
||||
{
|
||||
port_data = _nc_table_find_n(&ns->port_table, port);
|
||||
}
|
||||
if ((port_data != NULL) && (port_data->flags & NOTIFY_PORT_PROC_STATE_SUSPENDED))
|
||||
{
|
||||
c->suspend_count++;
|
||||
c->state_and_type |= NOTIFY_CLIENT_STATE_SUSPENDED;
|
||||
c->state_and_type |= NOTIFY_CLIENT_STATE_PENDING;
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
if (ns->flags & NOTIFY_STATE_ENABLE_RESEND) opts |= MACH_SEND_NOTIFY;
|
||||
|
||||
memset(&msg, 0, sizeof(mach_msg_empty_send_t));
|
||||
msg.header.msgh_size = sizeof(mach_msg_empty_send_t);
|
||||
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO);
|
||||
msg.header.msgh_local_port = MACH_PORT_NULL;
|
||||
msg.header.msgh_remote_port = port;
|
||||
msg.header.msgh_id = (mach_msg_id_t)c->cid.token;
|
||||
|
||||
kstatus = mach_msg(&msg.header, opts, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
|
||||
if (kstatus == MACH_SEND_TIMED_OUT)
|
||||
{
|
||||
/* deallocate port rights obtained via pseudo-receive after failed mach_msg() send */
|
||||
mach_msg_destroy(&msg.header);
|
||||
if (ns->flags & NOTIFY_STATE_ENABLE_RESEND)
|
||||
{
|
||||
/*
|
||||
* Suspend on timeout.
|
||||
* notifyd will get a MACH_NOTIFY_SEND_POSSIBLE and trigger a retry.
|
||||
* c->suspend_count must be zero, or we would not be trying to send.
|
||||
*/
|
||||
c->suspend_count++;
|
||||
c->state_and_type |= NOTIFY_CLIENT_STATE_SUSPENDED;
|
||||
c->state_and_type |= NOTIFY_CLIENT_STATE_PENDING;
|
||||
c->state_and_type |= NOTIFY_CLIENT_STATE_TIMEOUT;
|
||||
|
||||
if (port_data) {
|
||||
/*
|
||||
* If we failed to send, stop trying on this port
|
||||
* and just wait for the send-possible notification
|
||||
*/
|
||||
port_data->flags |= NOTIFY_PORT_PROC_STATE_SUSPENDED;
|
||||
}
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
return NOTIFY_STATUS_MACH_MSG_TIMEOUT;
|
||||
}
|
||||
else if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_MACH_MSG_FAILED;
|
||||
|
||||
c->state_and_type &= ~NOTIFY_CLIENT_STATE_PENDING;
|
||||
c->state_and_type &= ~NOTIFY_CLIENT_STATE_TIMEOUT;
|
||||
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send notification to a subscriber
|
||||
*/
|
||||
@ -368,7 +436,6 @@ static uint32_t
|
||||
_internal_send(notify_state_t *ns, client_t *c,
|
||||
proc_data_t *proc_data, port_data_t *port_data)
|
||||
{
|
||||
uint32_t send;
|
||||
|
||||
if (c->state_and_type & NOTIFY_CLIENT_STATE_SUSPENDED)
|
||||
{
|
||||
@ -388,9 +455,7 @@ _internal_send(notify_state_t *ns, client_t *c,
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
send = c->cid.token;
|
||||
|
||||
switch (c->state_and_type & NOTIFY_TYPE_MASK)
|
||||
switch (notify_get_type(c->state_and_type))
|
||||
{
|
||||
case NOTIFY_TYPE_SIGNAL:
|
||||
{
|
||||
@ -413,8 +478,8 @@ _internal_send(notify_state_t *ns, client_t *c,
|
||||
|
||||
if (c->deliver.fd >= 0)
|
||||
{
|
||||
send = htonl(send);
|
||||
len = write(c->deliver.fd, &send, sizeof(uint32_t));
|
||||
uint32_t send_value = htonl(c->cid.token);
|
||||
len = write(c->deliver.fd, &send_value, sizeof(uint32_t));
|
||||
if (len != sizeof(uint32_t))
|
||||
{
|
||||
close(c->deliver.fd);
|
||||
@ -431,62 +496,24 @@ _internal_send(notify_state_t *ns, client_t *c,
|
||||
|
||||
case NOTIFY_TYPE_PORT:
|
||||
{
|
||||
kern_return_t kstatus;
|
||||
mach_msg_empty_send_t msg;
|
||||
mach_msg_option_t opts = MACH_SEND_MSG | MACH_SEND_TIMEOUT;
|
||||
return _internal_send_port(ns, c, port_data, c->deliver.port);
|
||||
}
|
||||
|
||||
if (port_data == NULL)
|
||||
{
|
||||
port_data = _nc_table_find_n(&ns->port_table, c->deliver.port);
|
||||
}
|
||||
if ((port_data != NULL) && (port_data->flags & NOTIFY_PORT_PROC_STATE_SUSPENDED))
|
||||
{
|
||||
c->suspend_count++;
|
||||
c->state_and_type |= NOTIFY_CLIENT_STATE_SUSPENDED;
|
||||
c->state_and_type |= NOTIFY_CLIENT_STATE_PENDING;
|
||||
return NOTIFY_STATUS_OK;
|
||||
case NOTIFY_TYPE_XPC_EVENT:
|
||||
{
|
||||
xpc_object_t payload = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_string(payload, NOTIFY_XPC_EVENT_PAYLOAD_KEY_NAME, c->name_info->name);
|
||||
|
||||
name_info_t *n = _nc_table_find_64(&ns->name_id_table, c->name_info->name_id);
|
||||
if (n != NULL) {
|
||||
xpc_dictionary_set_uint64(payload, NOTIFY_XPC_EVENT_PAYLOAD_KEY_STATE, n->state);
|
||||
}
|
||||
|
||||
if (ns->flags & NOTIFY_STATE_ENABLE_RESEND) opts |= MACH_SEND_NOTIFY;
|
||||
|
||||
memset(&msg, 0, sizeof(mach_msg_empty_send_t));
|
||||
msg.header.msgh_size = sizeof(mach_msg_empty_send_t);
|
||||
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO);
|
||||
msg.header.msgh_local_port = MACH_PORT_NULL;
|
||||
msg.header.msgh_remote_port = c->deliver.port;
|
||||
msg.header.msgh_id = (mach_msg_id_t)send;
|
||||
|
||||
kstatus = mach_msg(&msg.header, opts, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
|
||||
if (kstatus == MACH_SEND_TIMED_OUT)
|
||||
{
|
||||
/* deallocate port rights obtained via pseudo-receive after failed mach_msg() send */
|
||||
mach_msg_destroy(&msg.header);
|
||||
if (ns->flags & NOTIFY_STATE_ENABLE_RESEND)
|
||||
{
|
||||
/*
|
||||
* Suspend on timeout.
|
||||
* notifyd will get a MACH_NOTIFY_SEND_POSSIBLE and trigger a retry.
|
||||
* c->suspend_count must be zero, or we would not be trying to send.
|
||||
*/
|
||||
c->suspend_count++;
|
||||
c->state_and_type |= NOTIFY_CLIENT_STATE_SUSPENDED;
|
||||
c->state_and_type |= NOTIFY_CLIENT_STATE_PENDING;
|
||||
c->state_and_type |= NOTIFY_CLIENT_STATE_TIMEOUT;
|
||||
|
||||
if (port_data) {
|
||||
/*
|
||||
* If we failed to send, stop trying on this port
|
||||
* and just wait for the send-possible notification
|
||||
*/
|
||||
port_data->flags |= NOTIFY_PORT_PROC_STATE_SUSPENDED;
|
||||
}
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
return NOTIFY_STATUS_MACH_MSG_TIMEOUT;
|
||||
int rc = xpc_event_publisher_fire_noboost(ns->event_publisher, c->deliver.event_token, payload);
|
||||
xpc_release(payload);
|
||||
if (rc != 0) {
|
||||
return NOTIFY_STATUS_TOKEN_FIRE_FAILED;
|
||||
}
|
||||
else if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_MACH_MSG_FAILED;
|
||||
|
||||
c->state_and_type &= ~NOTIFY_CLIENT_STATE_PENDING;
|
||||
c->state_and_type &= ~NOTIFY_CLIENT_STATE_TIMEOUT;
|
||||
@ -494,6 +521,15 @@ _internal_send(notify_state_t *ns, client_t *c,
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
case NOTIFY_TYPE_COMMON_PORT:
|
||||
{
|
||||
if (!proc_data || !proc_data->common_port_data)
|
||||
{
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
return _internal_send_port(ns, c, port_data, proc_data->common_port_data->port);
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
@ -845,7 +881,6 @@ _internal_register_common(notify_state_t *ns, const char *name, pid_t pid, int t
|
||||
{
|
||||
client_t *c;
|
||||
name_info_t *n;
|
||||
int is_new_name;
|
||||
uint32_t status;
|
||||
|
||||
if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
|
||||
@ -855,13 +890,10 @@ _internal_register_common(notify_state_t *ns, const char *name, pid_t pid, int t
|
||||
if (status != NOTIFY_STATUS_OK) return NOTIFY_STATUS_NOT_AUTHORIZED;
|
||||
|
||||
*outc = NULL;
|
||||
is_new_name = 0;
|
||||
|
||||
n = _nc_table_find(&ns->name_table, name);
|
||||
if (n == NULL)
|
||||
{
|
||||
is_new_name = 1;
|
||||
|
||||
n = _internal_new_name(ns, name);
|
||||
if (n == NULL) return NOTIFY_STATUS_NEW_NAME_FAILED;
|
||||
}
|
||||
@ -869,13 +901,7 @@ _internal_register_common(notify_state_t *ns, const char *name, pid_t pid, int t
|
||||
c = _internal_client_new(ns, pid, token, n);
|
||||
if (c == NULL)
|
||||
{
|
||||
if (is_new_name == 1)
|
||||
{
|
||||
_nc_table_delete(&ns->name_table, n->name);
|
||||
free(n);
|
||||
ns->stat_name_free++;
|
||||
}
|
||||
|
||||
_internal_release_name_info(ns, n);
|
||||
return NOTIFY_STATUS_NEW_CLIENT_FAILED;
|
||||
}
|
||||
|
||||
@ -886,7 +912,6 @@ _internal_register_common(notify_state_t *ns, const char *name, pid_t pid, int t
|
||||
|
||||
/*
|
||||
* Register for signal.
|
||||
* Returns the client_id;
|
||||
*/
|
||||
uint32_t
|
||||
_notify_lib_register_signal(notify_state_t *ns, const char *name, pid_t pid, int token, uint32_t sig, uid_t uid, gid_t gid, uint64_t *out_nid)
|
||||
@ -919,7 +944,6 @@ _notify_lib_register_signal(notify_state_t *ns, const char *name, pid_t pid, int
|
||||
|
||||
/*
|
||||
* Register for notification on a file descriptor.
|
||||
* Returns the client_id;
|
||||
*/
|
||||
uint32_t
|
||||
_notify_lib_register_file_descriptor(notify_state_t *ns, const char *name, pid_t pid, int token, int fd, uid_t uid, gid_t gid, uint64_t *out_nid)
|
||||
@ -952,7 +976,6 @@ _notify_lib_register_file_descriptor(notify_state_t *ns, const char *name, pid_t
|
||||
|
||||
/*
|
||||
* Register for notification on a mach port.
|
||||
* Returns the client_id;
|
||||
*/
|
||||
uint32_t
|
||||
_notify_lib_register_mach_port(notify_state_t *ns, const char *name, pid_t pid, int token, mach_port_t port, uid_t uid, gid_t gid, uint64_t *out_nid)
|
||||
@ -985,7 +1008,6 @@ _notify_lib_register_mach_port(notify_state_t *ns, const char *name, pid_t pid,
|
||||
|
||||
/*
|
||||
* Plain registration - only for notify_check()
|
||||
* Returns the client_id.
|
||||
*/
|
||||
uint32_t
|
||||
_notify_lib_register_plain(notify_state_t *ns, const char *name, pid_t pid, int token, uint32_t slot, uint32_t uid, uint32_t gid, uint64_t *out_nid)
|
||||
@ -1024,6 +1046,67 @@ _notify_lib_register_plain(notify_state_t *ns, const char *name, pid_t pid, int
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register for an XPC event notification
|
||||
*/
|
||||
uint32_t
|
||||
_notify_lib_register_xpc_event(notify_state_t *ns, const char *name, pid_t pid, int token, uint64_t event_token, uid_t uid, gid_t gid, uint64_t *out_nid)
|
||||
{
|
||||
client_t *c = NULL;
|
||||
uint32_t status;
|
||||
|
||||
if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
|
||||
|
||||
_notify_state_lock(&ns->lock);
|
||||
|
||||
assert(ns->event_publisher != NULL);
|
||||
|
||||
status = _internal_register_common(ns, name, pid, token, uid, gid, &c);
|
||||
if (status != NOTIFY_STATUS_OK)
|
||||
{
|
||||
_notify_state_unlock(&ns->lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
c->state_and_type &= ~NOTIFY_TYPE_MASK;
|
||||
c->state_and_type |= NOTIFY_TYPE_XPC_EVENT;
|
||||
c->deliver.event_token = event_token;
|
||||
*out_nid = c->name_info->name_id;
|
||||
|
||||
_notify_state_unlock(&ns->lock);
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register for notification on the common port.
|
||||
*/
|
||||
uint32_t
|
||||
_notify_lib_register_common_port(notify_state_t *ns, const char *name, pid_t pid, int token, uid_t uid, gid_t gid, uint64_t *out_nid)
|
||||
{
|
||||
client_t *c;
|
||||
uint32_t status;
|
||||
|
||||
if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
|
||||
|
||||
c = NULL;
|
||||
|
||||
_notify_state_lock(&ns->lock);
|
||||
|
||||
status = _internal_register_common(ns, name, pid, token, uid, gid, &c);
|
||||
if (status != NOTIFY_STATUS_OK)
|
||||
{
|
||||
_notify_state_unlock(&ns->lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
c->state_and_type &= ~NOTIFY_TYPE_MASK;
|
||||
c->state_and_type |= NOTIFY_TYPE_COMMON_PORT;
|
||||
*out_nid = c->name_info->name_id;
|
||||
|
||||
_notify_state_unlock(&ns->lock);
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
_notify_lib_set_owner(notify_state_t *ns, const char *name, uid_t uid, gid_t gid)
|
||||
{
|
||||
|
48
libnotify.h
48
libnotify.h
@ -29,6 +29,7 @@
|
||||
#include <pthread.h>
|
||||
#include <mach/mach.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <xpc/private.h>
|
||||
#include "table.h"
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
@ -51,22 +52,29 @@ extern const char *_notify_shm_id(void);
|
||||
#define NOTIFY_TYPE_NONE 0x00000000
|
||||
#define NOTIFY_TYPE_MEMORY 0x00000001
|
||||
#define NOTIFY_TYPE_PLAIN 0x00000002
|
||||
#define NOTIFY_TYPE_PORT 0x00000004
|
||||
#define NOTIFY_TYPE_FILE 0x00000008
|
||||
#define NOTIFY_TYPE_SIGNAL 0x00000010
|
||||
#define NOTIFY_TYPE_MASK 0x0000001f // If this is changed, make sure it doesn't muck with struct client_s
|
||||
#define NOTIFY_TYPE_PORT 0x00000003
|
||||
#define NOTIFY_TYPE_FILE 0x00000004
|
||||
#define NOTIFY_TYPE_SIGNAL 0x00000005
|
||||
#define NOTIFY_TYPE_XPC_EVENT 0x00000006
|
||||
#define NOTIFY_TYPE_COMMON_PORT 0x00000007
|
||||
|
||||
#define NOTIFY_TYPE_MASK 0x0000000f // If this is changed, make sure it doesn't muck with NOTIFY_CLIENT_STATE_*
|
||||
#define N_NOTIFY_TYPES 8
|
||||
|
||||
|
||||
#define NOTIFY_FLAG_SELF 0x80000000
|
||||
#define NOTIFY_FLAG_REGEN 0x40000000
|
||||
#define NOTIFY_FLAG_RELEASE_SEND 0x20000000
|
||||
#define NOTIFY_FLAG_DISPATCH 0x10000000
|
||||
#define NOTIFY_TYPE_COALESCE_BASE 0x08000000
|
||||
#define NOTIFY_TYPE_COALESCED 0x04000000
|
||||
#define NOTIFY_FLAG_COALESCE_BASE 0x08000000
|
||||
#define NOTIFY_FLAG_COALESCED 0x04000000
|
||||
#define NOTIFY_FLAG_RETAINED 0x02000000
|
||||
#define NOTIFY_FLAG_CANCELED 0x01000000
|
||||
#define NOTIFY_FLAG_SUSPENDED 0x00800000
|
||||
#define NOTIFY_FLAG_DEFERRED_POST 0x00400000
|
||||
|
||||
/* Used to check for a polled or delivered types */
|
||||
#define NOTIFY_TYPE_POLLED (NOTIFY_TYPE_MEMORY | NOTIFY_TYPE_PLAIN)
|
||||
#define NOTIFY_TYPE_DELIVERED (NOTIFY_TYPE_PORT | NOTIFY_TYPE_FILE | NOTIFY_TYPE_SIGNAL)
|
||||
#define notify_get_type(flags) ((flags) & NOTIFY_TYPE_MASK)
|
||||
#define notify_is_type(flags, type) (notify_get_type(flags) == (type))
|
||||
|
||||
/* Return values for notify_check() */
|
||||
#define NOTIFY_CHECK_FALSE 0
|
||||
@ -101,21 +109,25 @@ extern const char *_notify_shm_id(void);
|
||||
/* port_data_t::flags and proc_data_t::flags */
|
||||
#define PORT_PROC_FLAGS_NONE 0x00000000
|
||||
#define NOTIFY_PORT_PROC_STATE_SUSPENDED 0x00000001
|
||||
#define NOTIFY_PORT_FLAG_COMMON 0x00000002
|
||||
#define NOTIFY_PORT_FLAG_COMMON_READY_TO_FREE 0x00000004
|
||||
|
||||
/* notify state flags */
|
||||
#define NOTIFY_STATE_USE_LOCKS 0x00000001
|
||||
#define NOTIFY_STATE_ENABLE_RESEND 0x00000002
|
||||
|
||||
#define NOTIFY_XPC_EVENT_PAYLOAD_KEY_NAME "Notification"
|
||||
#define NOTIFY_XPC_EVENT_PAYLOAD_KEY_STATE "_State"
|
||||
|
||||
#define NOTIFY_CLIENT_SELF 0
|
||||
#define SIGNAL_NONE -1
|
||||
#define FD_NONE -1
|
||||
#define SLOT_NONE -1
|
||||
#define SLOT_NONE (uint32_t)~0
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LIST_HEAD(, client_s) subscriptions;
|
||||
char *name;
|
||||
void *private;
|
||||
uint64_t name_id;
|
||||
uint64_t state;
|
||||
uint64_t state_time;
|
||||
@ -134,6 +146,7 @@ typedef union client_delivery_u
|
||||
int fd;
|
||||
mach_port_t port;
|
||||
uint32_t sig;
|
||||
uint64_t event_token;
|
||||
} client_delivery_t;
|
||||
|
||||
typedef struct client_s
|
||||
@ -159,7 +172,7 @@ typedef struct client_s
|
||||
typedef struct
|
||||
{
|
||||
LIST_HEAD(, client_s) clients;
|
||||
uint32_t port;
|
||||
mach_port_t port;
|
||||
uint32_t flags;
|
||||
} port_data_t;
|
||||
|
||||
@ -169,8 +182,15 @@ typedef struct
|
||||
dispatch_source_t src;
|
||||
uint32_t pid;
|
||||
uint32_t flags;
|
||||
port_data_t *common_port_data;
|
||||
} proc_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
client_t *client;
|
||||
uint64_t event_token;
|
||||
} event_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* last allocated name id */
|
||||
@ -180,7 +200,9 @@ typedef struct
|
||||
table_64_t client_table;
|
||||
table_n_t port_table;
|
||||
table_n_t proc_table;
|
||||
table_64_t event_table;
|
||||
name_info_t **controlled_name;
|
||||
xpc_event_publisher_t event_publisher;
|
||||
uint32_t flags;
|
||||
uint32_t controlled_name_count;
|
||||
os_unfair_lock lock;
|
||||
@ -207,6 +229,8 @@ uint32_t _notify_lib_register_plain(notify_state_t *ns, const char *name, pid_t
|
||||
uint32_t _notify_lib_register_signal(notify_state_t *ns, const char *name, pid_t pid, int token, uint32_t sig, uint32_t uid, uint32_t gid, uint64_t *out_nid);
|
||||
uint32_t _notify_lib_register_mach_port(notify_state_t *ns, const char *name, pid_t pid, int token, mach_port_t port, uint32_t uid, uint32_t gid, uint64_t *out_nid);
|
||||
uint32_t _notify_lib_register_file_descriptor(notify_state_t *ns, const char *name, pid_t pid, int token, int fd, uint32_t uid, uint32_t gid, uint64_t *out_nid);
|
||||
uint32_t _notify_lib_register_xpc_event(notify_state_t *ns, const char *name, pid_t pid, int token, uint64_t event_token, uid_t uid, gid_t gid, uint64_t *out_nid);
|
||||
uint32_t _notify_lib_register_common_port(notify_state_t *ns, const char *name, pid_t pid, int token, uid_t uid, gid_t gid, uint64_t *out_nid);
|
||||
|
||||
uint32_t _notify_lib_set_owner(notify_state_t *ns, const char *name, uint32_t uid, uint32_t gid);
|
||||
uint32_t _notify_lib_set_access(notify_state_t *ns, const char *name, uint32_t access);
|
||||
|
10
notify.3
10
notify.3
@ -46,7 +46,7 @@
|
||||
.Fn notify_post "const char *name"
|
||||
.Ft uint32_t
|
||||
.Fn notify_register_check "const char *name, int *out_token"
|
||||
.Ft void
|
||||
.Ft typedef void
|
||||
.Fn (^notify_handler_t) "int token"
|
||||
.Ft uint32_t
|
||||
.Fn notify_register_dispatch "const char *name, int *out_token" "dispatch_queue_t queue" "notify_handler_t handler"
|
||||
@ -317,10 +317,10 @@ name convention used for Java package names and for System Preferences
|
||||
on Mac OS X.
|
||||
For example, "com.mydomain.example.event".
|
||||
.Pp
|
||||
Apple reserves the portion
|
||||
of the namespace prefixed by "com.apple.".
|
||||
This policy is not
|
||||
enforced in the current implementation, but may be in the future.
|
||||
Apple reserves the portion of the namespace prefixed by "com.apple.".
|
||||
This policy is not enforced in the current implementation, but may be in the
|
||||
future. It is enforced that the portion of the namespace prefixed by
|
||||
"com.apple.system." is reserved for root system process.
|
||||
.Pp
|
||||
Names in the space "user.uid.UID", where UID is a numeric user ID number
|
||||
are reserved for processes with that UID.
|
||||
|
28
notify.h
28
notify.h
@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2003-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 2003-2010 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
@ -11,7 +11,7 @@
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
@ -19,7 +19,7 @@
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
@ -64,12 +64,12 @@
|
||||
* for a name in rapid succession may result in a single notification sent
|
||||
* to clients registered for notification for that name. Clients checking
|
||||
* for changes using the notify_check() routine cannot determine if
|
||||
* more than one event pas been posted since a previous call to
|
||||
* more than one event pas been posted since a previous call to
|
||||
* notify_check() for that name.
|
||||
*
|
||||
* "False positives" may occur in notify_check() when used with a token
|
||||
* generated by notify_register_check() due to implementation constraints.
|
||||
* This behavior may vary in future releases.
|
||||
* This behavior may vary in future releases.
|
||||
*
|
||||
* Synchronization between two processes may be achieved using the
|
||||
* notify_set_state() and notify_get_state() routines.
|
||||
@ -123,7 +123,7 @@ OS_EXPORT uint32_t notify_post(const char *name);
|
||||
typedef void (^notify_handler_t)(int token);
|
||||
|
||||
/*!
|
||||
* @function notify_register
|
||||
* @function notify_register_dispatch
|
||||
* @abstract Request notification delivery to a dispatch queue.
|
||||
* @discussion When notifications are received by the process, the notify
|
||||
* subsystem will deliver the registered Block to the target
|
||||
@ -163,7 +163,7 @@ OS_EXPORT uint32_t notify_register_check(const char *name, int *out_token);
|
||||
* Request notification delivery by UNIX signal.
|
||||
*
|
||||
* A client may request signal notification for multiple names. After a signal
|
||||
* is delivered, the notify_check() routine may be called with each notification
|
||||
* is delivered, the notify_check() routine may be called with each notification
|
||||
* token to determine which name (if any) generated the signal notification.
|
||||
*
|
||||
* @param name (input) notification name
|
||||
@ -174,11 +174,11 @@ OS_EXPORT uint32_t notify_register_check(const char *name, int *out_token);
|
||||
OS_EXPORT uint32_t notify_register_signal(const char *name, int sig, int *out_token);
|
||||
|
||||
/*!
|
||||
* Request notification by mach message.
|
||||
* Request notification by mach message.
|
||||
*
|
||||
* Notifications are delivered by an empty message sent to a mach port.
|
||||
* By default, a new port is allocated and a pointer to it is returned
|
||||
* as the value of "notify_port". A mach port previously returned by a
|
||||
* as the value of "notify_port". A mach port previously returned by a
|
||||
* call to this routine may be used for notifications if a pointer to that
|
||||
* port is passed in to the routine and NOTIFY_REUSE is set in the flags
|
||||
* parameter. The notification service must be able to extract send
|
||||
@ -206,14 +206,14 @@ OS_EXPORT uint32_t notify_register_signal(const char *name, int sig, int *out_to
|
||||
OS_EXPORT uint32_t notify_register_mach_port(const char *name, mach_port_t *notify_port, int flags, int *out_token);
|
||||
|
||||
/*!
|
||||
* Request notification by a write to a file descriptor.
|
||||
* Request notification by a write to a file descriptor.
|
||||
*
|
||||
* Notifications are delivered by a write to a file descriptor.
|
||||
* By default, a new file descriptor is created and a pointer to it
|
||||
* is returned as the value of "notify_fd". A file descriptor created
|
||||
* by a previous call to this routine may be used for notifications if
|
||||
* a pointer to that file descriptor is passed in to the routine and
|
||||
* NOTIFY_REUSE is set in the flags parameter.
|
||||
* NOTIFY_REUSE is set in the flags parameter.
|
||||
*
|
||||
* Note that the kernel limits the buffer space for queued writes on a
|
||||
* file descriptor. If it is important that notifications should not be
|
||||
@ -256,8 +256,8 @@ OS_EXPORT uint32_t notify_check(int token, int *check);
|
||||
|
||||
/*!
|
||||
* Cancel notification and free resources associated with a notification
|
||||
* token. Mach ports and file descriptor associated with a token are released
|
||||
* (deallocated or closed) when all registration tokens associated with
|
||||
* token. Mach ports and file descriptor associated with a token are released
|
||||
* (deallocated or closed) when all registration tokens associated with
|
||||
* the port or file descriptor have been cancelled.
|
||||
*
|
||||
* @param token
|
||||
@ -296,7 +296,7 @@ __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0);
|
||||
/*!
|
||||
* Set or get a state value associated with a notification token.
|
||||
* Each key in the notification namespace has an associated integer value available
|
||||
* for use by clients as for application-specific purposes. A common usage is to
|
||||
* for use by clients as for application-specific purposes. A common usage is to
|
||||
* allow two processes or threads to synchronize their activities. For example, a
|
||||
* server process may need send a notification when a resource becomes available.
|
||||
* A client process can register for the notification, but when it starts up it will
|
||||
|
1264
notify_client.c
1264
notify_client.c
File diff suppressed because it is too large
Load Diff
@ -21,28 +21,18 @@
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#define __OS_EXPOSE_INTERNALS__ 1
|
||||
#include <os/internal/internal_shared.h>
|
||||
|
||||
#include <os/atomic_private.h>
|
||||
#include <os/crashlog_private.h>
|
||||
#include <os/lock.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <mach/mach.h>
|
||||
#include <os/lock.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#include "libnotify.h"
|
||||
|
||||
#define NOTIFY_INTERNAL_CRASH(c, x) __extension__({ \
|
||||
_os_set_crash_log_cause_and_message(c, "BUG IN LIBNOTIFY: " x); \
|
||||
__builtin_trap(); \
|
||||
})
|
||||
|
||||
#define NOTIFY_CLIENT_CRASH(c, x) __extension__({ \
|
||||
_os_set_crash_log_cause_and_message(c, \
|
||||
"BUG IN CLIENT OF LIBNOTIFY: " x); \
|
||||
__builtin_trap(); \
|
||||
})
|
||||
#define NOTIFY_INTERNAL_CRASH(c, x) OS_BUG_INTERNAL(c, "LIBNOTIFY", x)
|
||||
#define NOTIFY_CLIENT_CRASH(c, x) OS_BUG_CLIENT(c, "LIBNOTIFY", x)
|
||||
|
||||
#define NOTIFY_STATUS_SERVER_CHECKIN_FAILED 11
|
||||
// was NOTIFY_STATUS_LIB_SELF_STATE_FAILED 12
|
||||
@ -88,17 +78,24 @@
|
||||
#define NOTIFY_STATUS_TYPE_ISSUE 52
|
||||
#define NOTIFY_STATUS_PATH_NODE_CREATE_FAILED 53
|
||||
#define NOTIFY_STATUS_INVALID_TIME_EVENT 54
|
||||
#define NOTIFY_STATUS_TIMER_FAILED 55
|
||||
// No longer used: NOTIFY_STATUS_TIMER_FAILED 55
|
||||
#define NOTIFY_STATUS_DOUBLE_REG 56
|
||||
#define NOTIFY_STATUS_NO_REGEN_NEEDED 57
|
||||
#define NOTIFY_STATUS_TOKEN_FIRE_FAILED 58
|
||||
#define NOTIFY_STATUS_INVALID_PORT_INTERNAL 59
|
||||
#define NOTIFY_STATUS_NO_NID 60
|
||||
|
||||
#define IS_INTERNAL_ERROR(X) (X >= 11)
|
||||
|
||||
#define USER_PROTECTED_UID_PREFIX "user.uid."
|
||||
#define USER_PROTECTED_UID_PREFIX_LEN 9
|
||||
|
||||
#define CANARY_COUNT 13
|
||||
|
||||
struct notify_globals_s
|
||||
{
|
||||
uint64_t canary[CANARY_COUNT];
|
||||
|
||||
/* global lock */
|
||||
os_unfair_lock notify_lock;
|
||||
|
||||
|
@ -259,3 +259,29 @@ routine _notify_server_dump
|
||||
fileport : mach_port_move_send_t;
|
||||
ServerAuditToken audit : audit_token_t
|
||||
);
|
||||
|
||||
routine _notify_generate_common_port
|
||||
(
|
||||
server : mach_port_t;
|
||||
out status : uint32_t;
|
||||
out port : mach_port_move_receive_t;
|
||||
ServerAuditToken audit : audit_token_t
|
||||
);
|
||||
|
||||
simpleroutine _notify_server_register_common_port
|
||||
(
|
||||
server : mach_port_t;
|
||||
name : notify_name;
|
||||
token: int;
|
||||
ServerAuditToken audit : audit_token_t
|
||||
);
|
||||
|
||||
routine _notify_server_register_mach_port_3
|
||||
(
|
||||
server : mach_port_t;
|
||||
name : notify_name;
|
||||
token: int;
|
||||
out status : uint32_t;
|
||||
out port : mach_port_move_receive_t;
|
||||
ServerAuditToken audit : audit_token_t
|
||||
);
|
||||
|
@ -56,8 +56,12 @@ __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_3);
|
||||
OS_EXPORT uint32_t notify_peek(int token, uint32_t *val)
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_3);
|
||||
|
||||
// This SPI requires a sandbox exception in notifyd and will fail silently for
|
||||
// new clients or new filepaths from existing clients. It is reccomended that
|
||||
// both existing and new clients use some other file monitoring system, such as
|
||||
// dispatch_source or FSEvents.
|
||||
OS_EXPORT uint32_t notify_monitor_file(int token, char *path, int flags)
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_3);
|
||||
__API_DEPRECATED("No longer supported for new clients", macos(10.7, 10.16), ios(4.3, 14.0), watchos(1.0, 7.0), tvos(1.0, 14.0));
|
||||
|
||||
OS_EXPORT uint32_t notify_get_event(int token, int *ev, char *buf, int *len)
|
||||
__API_DEPRECATED("No longer supported", macos(10.7, 10.15), ios(4.3, 13.0), watchos(1.0, 6.0), tvos(1.0, 13.0));
|
||||
|
@ -1,16 +0,0 @@
|
||||
// fake DTrace probes for libnotify
|
||||
|
||||
#define NOTIFY_REGISTER_MACH_PORT(...) (0)
|
||||
#define NOTIFY_REGISTER_MACH_PORT_ENABLED(...) (0)
|
||||
|
||||
#define NOTIFY_POST(...) (0)
|
||||
#define NOTIFY_POST_ENABLED(...) (0)
|
||||
|
||||
#define NOTIFY_CHECK(...) (0)
|
||||
#define NOTIFY_CHECK_ENABLED(...) (0)
|
||||
|
||||
#define NOTIFY_DELIVER_START(...) (0)
|
||||
#define NOTIFY_DELIVER_START_ENABLED(...) (0)
|
||||
|
||||
#define NOTIFY_DELIVER_END(...) (0)
|
||||
#define NOTIFY_DELIVER_END_ENABLED(...) (0)
|
@ -117,7 +117,6 @@ main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t r;
|
||||
kern_return_t kr;
|
||||
unsigned i, j;
|
||||
|
||||
kr = mach_timebase_info(&tbi);
|
||||
assert(!kr);
|
||||
@ -140,7 +139,7 @@ main(int argc, char *argv[])
|
||||
|
||||
dispatch_queue_t disp_q = dispatch_queue_create("Notify.Test", NULL);
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "-c")) cnt = atoi(argv[++i]);
|
||||
else if (!strcmp(argv[i], "-s")) spl = atoi(argv[++i]) + 1;
|
||||
@ -149,12 +148,12 @@ main(int argc, char *argv[])
|
||||
if (cnt > MAX_CNT) cnt = MAX_CNT;
|
||||
if (spl > MAX_SPL) spl = MAX_SPL + 1;
|
||||
|
||||
for (j = 0 ; j < spl; j++)
|
||||
for (uint32_t j = 0 ; j < spl; j++)
|
||||
{
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = asprintf(&n[i], "dummy.test.%d", i);
|
||||
assert(r != -1);
|
||||
assert(r != (uint32_t)~0);
|
||||
l[i] = strlen(n[i]);
|
||||
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &p[i]);
|
||||
assert(kr == 0);
|
||||
@ -162,7 +161,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Empty Loop */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
spin++;
|
||||
}
|
||||
@ -170,7 +169,7 @@ main(int argc, char *argv[])
|
||||
|
||||
#ifdef NO_OP_TESTS
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_no_op_str_sync(n[i], l[i]);
|
||||
assert(r == 0);
|
||||
@ -178,7 +177,7 @@ main(int argc, char *argv[])
|
||||
nss[j] = mach_absolute_time() - s;
|
||||
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_no_op_str_async(n[i], l[i]);
|
||||
assert(r == 0);
|
||||
@ -186,7 +185,7 @@ main(int argc, char *argv[])
|
||||
nsa[j] = mach_absolute_time() - s;
|
||||
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_no_op_int_sync(i);
|
||||
assert(r == 0);
|
||||
@ -208,7 +207,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Register Plain */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_register_plain(n[i], &t[i]);
|
||||
assert(r == 0);
|
||||
@ -217,7 +216,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Post 1 */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_post(n[i]);
|
||||
assert(r == 0);
|
||||
@ -226,7 +225,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Post 2 */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_post(n[i]);
|
||||
assert(r == 0);
|
||||
@ -235,7 +234,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Post 3 */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_post(n[i]);
|
||||
assert(r == 0);
|
||||
@ -244,7 +243,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Cancel Plain */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_cancel(t[i]);
|
||||
assert(r == 0);
|
||||
@ -253,7 +252,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Register Mach Port */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_register_mach_port(n[i], &p[i], NOTIFY_REUSE, &t[i]);
|
||||
assert(r == 0);
|
||||
@ -263,7 +262,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Set State 1 */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_set_state(t[i], 1);
|
||||
assert(r == 0);
|
||||
@ -272,7 +271,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Get State */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
uint64_t dummy;
|
||||
r = notify_get_state(t[i], &dummy);
|
||||
@ -282,7 +281,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Set State 2 */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_set_state(t[i], 2);
|
||||
assert(r == 0);
|
||||
@ -291,7 +290,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Cancel Port */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_cancel(t[i]);
|
||||
assert(r == 0);
|
||||
@ -302,7 +301,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Register Check */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_register_check("com.apple.notify.test.check", &t[i]);
|
||||
assert(r == 0);
|
||||
@ -311,7 +310,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Check 1 */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_check(t[i], &check);
|
||||
assert(r == 0);
|
||||
@ -321,7 +320,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Check 2 */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_check(t[i], &check);
|
||||
assert(r == 0);
|
||||
@ -331,7 +330,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Check 3 */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_check(t[i], &check);
|
||||
assert(r == 0);
|
||||
@ -345,7 +344,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Check 4 */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_check(t[i], &check);
|
||||
assert(r == 0);
|
||||
@ -355,7 +354,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Check 5 */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_check(t[i], &check);
|
||||
assert(r == 0);
|
||||
@ -365,7 +364,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Cancel Check */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_cancel(t[i]);
|
||||
assert(r == 0);
|
||||
@ -374,7 +373,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Register Dispatch 1 */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_register_dispatch(n[i], &t[i], disp_q, ^(int x){
|
||||
dispatch_changer = x;
|
||||
@ -385,7 +384,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Register Dispatch 2 (Coalesced) */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_register_dispatch(n[i], &t_2[i], disp_q, ^(int x){
|
||||
dispatch_changer = x;
|
||||
@ -397,7 +396,7 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Cancel Dispatch */
|
||||
s = mach_absolute_time();
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
r = notify_cancel(t[i]);
|
||||
assert(r == 0);
|
||||
@ -406,7 +405,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
cancel_disp[j] = mach_absolute_time() - s;
|
||||
|
||||
for (i = 0; i < cnt; i++)
|
||||
for (uint32_t i = 0; i < cnt; i++)
|
||||
{
|
||||
free(n[i]);
|
||||
kr = mach_port_mod_refs(mach_task_self(), p[i], MACH_PORT_RIGHT_RECEIVE, -1);
|
||||
|
@ -18,15 +18,12 @@
|
||||
<key>com.apple.system.notification_center</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>PublishesEvents</key>
|
||||
<string>com.apple.notifyd.matching</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/sbin/notifyd</string>
|
||||
</array>
|
||||
<key>JetsamProperties</key>
|
||||
<dict>
|
||||
<key>JetsamPriority</key>
|
||||
<integer>-1000</integer>
|
||||
</dict>
|
||||
<key>POSIXSpawnType</key>
|
||||
<string>Interactive</string>
|
||||
</dict>
|
||||
|
10
notifyd/entitlements.plist
Normal file
10
notifyd/entitlements.plist
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>seatbelt-profiles</key>
|
||||
<array>
|
||||
<string>notifyd</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
@ -1 +0,0 @@
|
||||
../../../../Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/mach/notify.defs
|
@ -1 +0,0 @@
|
||||
../notify_ipc.defs
|
@ -31,7 +31,9 @@
|
||||
#include <mach/mach_error.h>
|
||||
#include <mach/mach_traps.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/kauth.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <dispatch/private.h>
|
||||
#include <assert.h>
|
||||
@ -43,6 +45,8 @@
|
||||
#include "notifyServer.h"
|
||||
#include <sandbox.h>
|
||||
|
||||
static inline void proc_cancel(proc_data_t *pdata);
|
||||
|
||||
static void
|
||||
port_arm_mach_notifications(mach_port_t port)
|
||||
{
|
||||
@ -78,6 +82,24 @@ port_free(void *_pp)
|
||||
free(pdata);
|
||||
}
|
||||
|
||||
// This should be called either when the process cleans up, or when the process
|
||||
// forgets about a common port, such as after an exec.
|
||||
static void
|
||||
common_port_free(port_data_t *common_port_data) {
|
||||
// Common port registrations should not be freed until both the mach port cleanup and the process
|
||||
// cleanup is done. Whichever happens first sets the _READY_TO_FREE flags, and whichever happens
|
||||
// second frees.
|
||||
if (common_port_data->flags & NOTIFY_PORT_FLAG_COMMON_READY_TO_FREE) {
|
||||
if (!LIST_EMPTY(&common_port_data->clients)) {
|
||||
NOTIFY_INTERNAL_CRASH(0, "port_proc still had clients");
|
||||
}
|
||||
log_message(ASL_LEVEL_DEBUG, "do_mach_notify_dead_name freed port %x\n", (unsigned int)common_port_data);
|
||||
port_free(common_port_data);
|
||||
} else {
|
||||
common_port_data->flags |= NOTIFY_PORT_FLAG_COMMON_READY_TO_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
proc_free(void *_pp)
|
||||
{
|
||||
@ -92,13 +114,29 @@ proc_free(void *_pp)
|
||||
|
||||
ns->stat_portproc_free++;
|
||||
|
||||
if (pdata->common_port_data) {
|
||||
common_port_free(pdata->common_port_data);
|
||||
}
|
||||
|
||||
dispatch_release(pdata->src);
|
||||
free(pdata);
|
||||
}
|
||||
|
||||
static void
|
||||
proc_create(notify_state_t *ns, client_t *c, pid_t proc, dispatch_source_t src)
|
||||
proc_event(void *_pp)
|
||||
{
|
||||
proc_data_t *pdata = _pp;
|
||||
|
||||
proc_cancel(pdata);
|
||||
}
|
||||
|
||||
static proc_data_t *
|
||||
proc_create(notify_state_t *ns, client_t *c, pid_t pid)
|
||||
{
|
||||
dispatch_source_t src = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid,
|
||||
DISPATCH_PROC_EXIT, global.workloop);
|
||||
dispatch_source_set_event_handler_f(src, proc_event);
|
||||
|
||||
proc_data_t *pdata = malloc(sizeof(proc_data_t));
|
||||
|
||||
if (pdata == NULL) {
|
||||
@ -112,18 +150,25 @@ proc_create(notify_state_t *ns, client_t *c, pid_t proc, dispatch_source_t src)
|
||||
LIST_INIT(&pdata->clients);
|
||||
pdata->src = src;
|
||||
pdata->flags = PORT_PROC_FLAGS_NONE;
|
||||
pdata->pid = proc;
|
||||
pdata->pid = (uint32_t)pid;
|
||||
pdata->common_port_data = NULL;
|
||||
_nc_table_insert_n(&ns->proc_table, &pdata->pid);
|
||||
LIST_INSERT_HEAD(&pdata->clients, c, client_pid_entry);
|
||||
if(c) {
|
||||
LIST_INSERT_HEAD(&pdata->clients, c, client_pid_entry);
|
||||
}
|
||||
|
||||
dispatch_set_context(src, pdata);
|
||||
dispatch_source_set_cancel_handler_f(src, proc_free);
|
||||
dispatch_activate(src);
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static void
|
||||
// Returns true on success
|
||||
static bool
|
||||
port_create(notify_state_t *ns, client_t *c, mach_port_t port)
|
||||
{
|
||||
kern_return_t kstatus;
|
||||
port_data_t *pdata = calloc(1, sizeof(port_data_t));
|
||||
|
||||
if (pdata == NULL) {
|
||||
@ -139,20 +184,57 @@ port_create(notify_state_t *ns, client_t *c, mach_port_t port)
|
||||
_nc_table_insert_n(&ns->port_table, &pdata->port);
|
||||
LIST_INSERT_HEAD(&pdata->clients, c, client_port_entry);
|
||||
|
||||
mach_port_insert_right(mach_task_self(), port, port,
|
||||
MACH_MSG_TYPE_COPY_SEND);
|
||||
kstatus = mach_port_insert_right(mach_task_self(), port,
|
||||
port, MACH_MSG_TYPE_COPY_SEND);
|
||||
if (kstatus != KERN_SUCCESS) {
|
||||
// This will fail if the port is dead
|
||||
return false;
|
||||
}
|
||||
/* arming SEND_POSSIBLE must be done before we attempt any send */
|
||||
port_arm_mach_notifications(port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
static port_data_t *
|
||||
common_port_create(notify_state_t *ns, mach_port_t port)
|
||||
{
|
||||
port_data_t *pdata = calloc(1, sizeof(port_data_t));
|
||||
|
||||
if (pdata == NULL) {
|
||||
// failing here is not an option, and our malloc will never fail
|
||||
// for such a small allocation
|
||||
NOTIFY_INTERNAL_CRASH(0, "Unable to allocate portproc");
|
||||
}
|
||||
|
||||
ns->stat_portproc_alloc++;
|
||||
|
||||
LIST_INIT(&pdata->clients);
|
||||
pdata->port = port;
|
||||
pdata->flags = NOTIFY_PORT_FLAG_COMMON;
|
||||
_nc_table_insert_n(&ns->port_table, &pdata->port);
|
||||
|
||||
/* arming SEND_POSSIBLE must be done before we attempt any send */
|
||||
port_arm_mach_notifications(port);
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static proc_data_t *
|
||||
proc_register(notify_state_t *ns, client_t *c, pid_t pid)
|
||||
{
|
||||
proc_data_t *pdata = _nc_table_find_n(&ns->proc_table, pid);
|
||||
if (pdata) {
|
||||
if (pdata && c) {
|
||||
LIST_INSERT_HEAD(&pdata->clients, c, client_pid_entry);
|
||||
}
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static void proc_add_client(proc_data_t *pdata,client_t *c, pid_t pid)
|
||||
{
|
||||
if (pdata && c) {
|
||||
LIST_INSERT_HEAD(&pdata->clients, c, client_pid_entry);
|
||||
}
|
||||
return pdata != NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -226,17 +308,12 @@ port_proc_cancel_client(client_t *c)
|
||||
|
||||
n = c->name_info;
|
||||
assert(n != NULL);
|
||||
if ((n->refcount == 1) && (n->private != NULL))
|
||||
{
|
||||
service_close(n->private);
|
||||
n->private = NULL;
|
||||
}
|
||||
|
||||
if (c->state_and_type & NOTIFY_TYPE_MEMORY)
|
||||
if (notify_is_type(c->state_and_type, NOTIFY_TYPE_MEMORY))
|
||||
{
|
||||
global.shared_memory_refcount[n->slot]--;
|
||||
}
|
||||
else if (c->state_and_type & NOTIFY_TYPE_PORT)
|
||||
else if (notify_is_type(c->state_and_type, NOTIFY_TYPE_PORT) || notify_is_type(c->state_and_type, NOTIFY_TYPE_COMMON_PORT))
|
||||
{
|
||||
LIST_REMOVE(c, client_port_entry);
|
||||
}
|
||||
@ -272,7 +349,19 @@ do_mach_notify_dead_name(mach_port_t notify, mach_port_name_t port)
|
||||
LIST_FOREACH_SAFE(c, &pdata->clients, client_port_entry, tmp) {
|
||||
port_proc_cancel_client(c);
|
||||
}
|
||||
port_free(pdata);
|
||||
if (pdata->flags & NOTIFY_PORT_FLAG_COMMON) {
|
||||
// Common port registrations should not be freed until both the mach port cleanup and the process
|
||||
// cleanup is done. Whichever happens first sets the _READY_TO_FREE flags, and whichever happens
|
||||
// second frees.
|
||||
if (pdata->flags & NOTIFY_PORT_FLAG_COMMON_READY_TO_FREE) {
|
||||
log_message(ASL_LEVEL_DEBUG, "do_mach_notify_dead_name freed port %x\n", (unsigned int)port);
|
||||
port_free(pdata);
|
||||
} else {
|
||||
pdata->flags |= NOTIFY_PORT_FLAG_COMMON_READY_TO_FREE;
|
||||
}
|
||||
} else {
|
||||
port_free(pdata);
|
||||
}
|
||||
|
||||
// the act of receiving a dead name notification allocates a dead-name
|
||||
// right that must be deallocated
|
||||
@ -280,41 +369,63 @@ do_mach_notify_dead_name(mach_port_t notify, mach_port_name_t port)
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
proc_event(void *_pp)
|
||||
{
|
||||
proc_data_t *pdata = _pp;
|
||||
|
||||
proc_cancel(pdata);
|
||||
}
|
||||
|
||||
static void
|
||||
static proc_data_t *
|
||||
register_proc(client_t *c, pid_t pid)
|
||||
{
|
||||
dispatch_source_t src;
|
||||
if (pid <= 0) return NULL;
|
||||
proc_data_t *result = NULL;
|
||||
|
||||
if (pid <= 0) return;
|
||||
|
||||
if (proc_register(&global.notify_state, c, pid)) {
|
||||
return;
|
||||
if ((result = proc_register(&global.notify_state, c, pid)) != NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
src = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid,
|
||||
DISPATCH_PROC_EXIT, global.workloop);
|
||||
dispatch_source_set_event_handler_f(src, proc_event);
|
||||
|
||||
proc_create(&global.notify_state, c, pid, src);
|
||||
return proc_create(&global.notify_state, c, pid);
|
||||
}
|
||||
|
||||
static void
|
||||
// Returns true on success
|
||||
static bool
|
||||
register_port(client_t *c, mach_port_t port)
|
||||
{
|
||||
if (port_register(&global.notify_state, c, port)) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
port_create(&global.notify_state, c, port);
|
||||
return port_create(&global.notify_state, c, port);
|
||||
}
|
||||
|
||||
static void
|
||||
register_xpc_event(client_t *c, uint64_t event_token)
|
||||
{
|
||||
event_data_t *edata = _nc_table_find_64(&global.notify_state.event_table, event_token);
|
||||
if (edata != NULL) {
|
||||
NOTIFY_INTERNAL_CRASH(event_token, "Event token is already registered");
|
||||
}
|
||||
|
||||
edata = calloc(1, sizeof(event_data_t));
|
||||
edata->client = c;
|
||||
edata->event_token = event_token;
|
||||
|
||||
_nc_table_insert_64(&global.notify_state.event_table, &edata->event_token);
|
||||
|
||||
global.notify_state.stat_portproc_alloc++;
|
||||
}
|
||||
|
||||
static client_t *
|
||||
cancel_xpc_event(uint64_t event_token)
|
||||
{
|
||||
event_data_t *edata = _nc_table_find_64(&global.notify_state.event_table, event_token);
|
||||
if (edata == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
client_t *client = edata->client;
|
||||
|
||||
_nc_table_delete_64(&global.notify_state.event_table, event_token);
|
||||
free(edata);
|
||||
|
||||
global.notify_state.stat_portproc_free++;
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
@ -351,7 +462,6 @@ server_preflight(audit_token_t audit, int token, uid_t *uid, gid_t *gid, pid_t *
|
||||
*pid = xpid;
|
||||
}
|
||||
|
||||
if (token > 0)
|
||||
{
|
||||
client_t *c;
|
||||
uint64_t xcid = make_client_id(xpid, token);
|
||||
@ -454,7 +564,7 @@ kern_return_t __notify_server_post_2
|
||||
|
||||
if (n == NULL)
|
||||
{
|
||||
*status = NOTIFY_STATUS_INVALID_NAME;
|
||||
*status = NOTIFY_STATUS_NO_NID;
|
||||
*name_id = UINT64_MAX;
|
||||
call_statistics.post_no_op++;
|
||||
}
|
||||
@ -499,7 +609,7 @@ kern_return_t __notify_server_register_plain_2
|
||||
)
|
||||
{
|
||||
client_t *c;
|
||||
uint64_t nid, cid;
|
||||
uint64_t nid, cid = 0;
|
||||
uint32_t status;
|
||||
uid_t uid = (uid_t)-1;
|
||||
gid_t gid = (gid_t)-1;
|
||||
@ -541,7 +651,7 @@ kern_return_t __notify_server_register_check_2
|
||||
{
|
||||
name_info_t *n;
|
||||
uint32_t i, j, x, new_slot;
|
||||
uint64_t cid;
|
||||
uint64_t cid = 0;
|
||||
client_t *c;
|
||||
uid_t uid = (uid_t)-1;
|
||||
gid_t gid = (gid_t)-1;
|
||||
@ -644,7 +754,7 @@ kern_return_t __notify_server_register_signal_2
|
||||
)
|
||||
{
|
||||
client_t *c;
|
||||
uint64_t name_id, cid;
|
||||
uint64_t name_id, cid = 0;
|
||||
uint32_t status;
|
||||
uid_t uid = (uid_t)-1;
|
||||
gid_t gid = (gid_t)-1;
|
||||
@ -684,7 +794,7 @@ kern_return_t __notify_server_register_file_descriptor_2
|
||||
client_t *c;
|
||||
int fd, flags;
|
||||
uint32_t status;
|
||||
uint64_t name_id, cid;
|
||||
uint64_t name_id, cid = 0;
|
||||
uid_t uid = (uid_t)-1;
|
||||
gid_t gid = (gid_t)-1;
|
||||
pid_t pid = (pid_t)-1;
|
||||
@ -730,9 +840,8 @@ kern_return_t __notify_server_register_file_descriptor_2
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
kern_return_t __notify_server_register_mach_port_2
|
||||
static uint32_t _notify_register_mach_port_helper
|
||||
(
|
||||
mach_port_t server,
|
||||
caddr_t name,
|
||||
int token,
|
||||
mach_port_t port,
|
||||
@ -740,7 +849,7 @@ kern_return_t __notify_server_register_mach_port_2
|
||||
)
|
||||
{
|
||||
client_t *c;
|
||||
uint64_t name_id, cid;
|
||||
uint64_t name_id, cid = 0;
|
||||
uint32_t status;
|
||||
uid_t uid = (uid_t)-1;
|
||||
gid_t gid = (gid_t)-1;
|
||||
@ -748,7 +857,7 @@ kern_return_t __notify_server_register_mach_port_2
|
||||
|
||||
if (port == MACH_PORT_DEAD || port == MACH_PORT_NULL)
|
||||
{
|
||||
return KERN_SUCCESS;
|
||||
return NOTIFY_STATUS_INVALID_PORT_INTERNAL;
|
||||
}
|
||||
|
||||
server_preflight(audit, token, &uid, &gid, &pid, &cid);
|
||||
@ -762,15 +871,42 @@ kern_return_t __notify_server_register_mach_port_2
|
||||
if (status != NOTIFY_STATUS_OK)
|
||||
{
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
return KERN_SUCCESS;
|
||||
return NOTIFY_STATUS_NOT_AUTHORIZED;
|
||||
}
|
||||
|
||||
c = _nc_table_find_64(&global.notify_state.client_table,cid);
|
||||
c = _nc_table_find_64(&global.notify_state.client_table, cid);
|
||||
|
||||
if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, audit);
|
||||
|
||||
register_proc(c, pid);
|
||||
register_port(c, port);
|
||||
bool success = register_port(c, port);
|
||||
if (!success) {
|
||||
port_proc_cancel_client(c);
|
||||
}
|
||||
|
||||
// The mach_port_dealloc of port is done when the registration is cancelled
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
kern_return_t __notify_server_register_mach_port_2
|
||||
(
|
||||
mach_port_t server,
|
||||
caddr_t name,
|
||||
int token,
|
||||
mach_port_t port,
|
||||
audit_token_t audit
|
||||
)
|
||||
{
|
||||
notify_state_t *ns = &global.notify_state;
|
||||
|
||||
if (_nc_table_find_n(&ns->port_table, port) == NULL)
|
||||
{
|
||||
// Port was not created by notifyd
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
(void)_notify_register_mach_port_helper(name, token, port, audit);
|
||||
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
@ -1172,7 +1308,6 @@ kern_return_t __notify_server_regenerate
|
||||
audit_token_t audit
|
||||
)
|
||||
{
|
||||
kern_return_t kstatus;
|
||||
pid_t pid = (pid_t)-1;
|
||||
int size;
|
||||
name_info_t *n;
|
||||
@ -1206,16 +1341,16 @@ kern_return_t __notify_server_regenerate
|
||||
case NOTIFY_TYPE_MEMORY:
|
||||
{
|
||||
/* prev_slot must be between 0 and global.nslots */
|
||||
if ((prev_slot < 0) || (prev_slot >= global.nslots))
|
||||
if ((uint32_t)prev_slot >= global.nslots)
|
||||
{
|
||||
*status = NOTIFY_STATUS_INVALID_REQUEST;
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
kstatus = __notify_server_register_check_2(server, name, token, &size, new_slot, new_nid, status, audit);
|
||||
(void)__notify_server_register_check_2(server, name, token, &size, (int *)new_slot, new_nid, status, audit);
|
||||
if (*status == NOTIFY_STATUS_OK)
|
||||
{
|
||||
if ((*new_slot != UINT32_MAX) && (global.last_shm_base != NULL))
|
||||
if (((uint32_t)*new_slot != SLOT_NONE) && (global.last_shm_base != NULL))
|
||||
{
|
||||
global.shared_memory_base[*new_slot] = global.shared_memory_base[*new_slot] + global.last_shm_base[prev_slot] - 1;
|
||||
global.last_shm_base[prev_slot] = 0;
|
||||
@ -1225,19 +1360,20 @@ kern_return_t __notify_server_regenerate
|
||||
}
|
||||
case NOTIFY_TYPE_PLAIN:
|
||||
{
|
||||
kstatus = __notify_server_register_plain_2(server, name, token, audit);
|
||||
break;
|
||||
}
|
||||
case NOTIFY_TYPE_PORT:
|
||||
{
|
||||
kstatus = __notify_server_register_mach_port_2(server, name, token, port, audit);
|
||||
(void)__notify_server_register_plain_2(server, name, token, audit);
|
||||
break;
|
||||
}
|
||||
case NOTIFY_TYPE_SIGNAL:
|
||||
{
|
||||
kstatus = __notify_server_register_signal_2(server, name, token, sig, audit);
|
||||
(void)__notify_server_register_signal_2(server, name, token, sig, audit);
|
||||
break;
|
||||
}
|
||||
case NOTIFY_TYPE_COMMON_PORT:
|
||||
{
|
||||
(void)__notify_server_register_common_port(server, name, token, audit);
|
||||
break;
|
||||
}
|
||||
case NOTIFY_TYPE_PORT:
|
||||
case NOTIFY_TYPE_FILE: /* fall through */
|
||||
default:
|
||||
{
|
||||
@ -1348,3 +1484,228 @@ kern_return_t __notify_server_dump
|
||||
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
static uid_t
|
||||
xpc_event_token_get_uid(uint64_t event_token)
|
||||
{
|
||||
#if TARGET_OS_OSX
|
||||
au_asid_t asid = xpc_event_publisher_get_subscriber_asid(global.notify_state.event_publisher, event_token);
|
||||
|
||||
auditinfo_addr_t info = { 0 };
|
||||
info.ai_asid = asid;
|
||||
|
||||
int ret = auditon(A_GETSINFO_ADDR, &info, sizeof(info));
|
||||
if (ret != 0) {
|
||||
log_message(ASL_LEVEL_WARNING, "auditon on asid %d failed with errno %d, skipping registration\n", asid, errno);
|
||||
return KAUTH_UID_NONE;
|
||||
}
|
||||
|
||||
return info.ai_auid;
|
||||
#else // TARGET_OS_OSX
|
||||
// XPC event registrations historically bypassed UID permission checks on
|
||||
// iOS since those were coming from UEA running as root. Preserve that and
|
||||
// return root UID.
|
||||
// There isn't a way to obtain the UID for an event token on iOS.
|
||||
// rdar://problem/50776875
|
||||
(void)event_token;
|
||||
return 0; // root
|
||||
#endif // TARGET_OS_OSX
|
||||
}
|
||||
|
||||
void
|
||||
notifyd_matching_register(uint64_t event_token, xpc_object_t descriptor)
|
||||
{
|
||||
assert(xpc_get_type(descriptor) == XPC_TYPE_DICTIONARY);
|
||||
const char *name = xpc_dictionary_get_string(descriptor, NOTIFY_XPC_EVENT_PAYLOAD_KEY_NAME);
|
||||
|
||||
// Use bogus PID for XPC event registrations
|
||||
pid_t pid = -1;
|
||||
int token = global.next_no_client_token++;
|
||||
|
||||
call_statistics.reg++;
|
||||
call_statistics.reg_xpc_event++;
|
||||
|
||||
log_message(ASL_LEVEL_DEBUG, "notifyd_matching_register %s %d %llu\n", name, token, event_token);
|
||||
|
||||
uid_t uid = xpc_event_token_get_uid(event_token);
|
||||
if (uid == KAUTH_UID_NONE) {
|
||||
return;
|
||||
}
|
||||
// notifyd can't call getpwuid_r to find out GID for UID as it deadlocks
|
||||
// with opendirectoryd. Use bogus GID to fail group access checks if any.
|
||||
gid_t gid = KAUTH_GID_NONE;
|
||||
|
||||
uint64_t unused_nid = 0;
|
||||
uint32_t status = _notify_lib_register_xpc_event(&global.notify_state, name, pid, token, event_token, uid, gid, &unused_nid);
|
||||
if (status != NOTIFY_STATUS_OK) {
|
||||
if (status != NOTIFY_STATUS_NOT_AUTHORIZED) {
|
||||
log_message(ASL_LEVEL_WARNING, "_notify_lib_register_xpc_event failed with status %u\n", status);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
client_t *c = _nc_table_find_64(&global.notify_state.client_table, make_client_id(pid, token));
|
||||
if (c == NULL) {
|
||||
NOTIFY_INTERNAL_CRASH(0, "Can't find client after registering an event");
|
||||
}
|
||||
|
||||
// Don't register_proc since PID is bogus
|
||||
register_xpc_event(c, event_token);
|
||||
}
|
||||
|
||||
void
|
||||
notifyd_matching_unregister(uint64_t event_token)
|
||||
{
|
||||
client_t *c = cancel_xpc_event(event_token);
|
||||
if (c == NULL) {
|
||||
return; // if registration was denied, there wouldn't be anything to unregister
|
||||
}
|
||||
|
||||
_notify_lib_cancel_client(&global.notify_state, c);
|
||||
}
|
||||
|
||||
kern_return_t __notify_generate_common_port
|
||||
(
|
||||
mach_port_t server,
|
||||
uint32_t *status,
|
||||
mach_port_t *out_port,
|
||||
audit_token_t audit
|
||||
)
|
||||
{
|
||||
mach_port_t port;
|
||||
kern_return_t kstatus;
|
||||
|
||||
*status = NOTIFY_STATUS_OK;
|
||||
*out_port = MACH_PORT_NULL;
|
||||
|
||||
pid_t pid = audit_token_to_pid(audit);
|
||||
|
||||
log_message(ASL_LEVEL_DEBUG, "__notify_generate_common_port %d\n", pid);
|
||||
|
||||
// Create a proc object if one doesn't exist
|
||||
notify_state_t *ns = &global.notify_state;
|
||||
proc_data_t *pdata = _nc_table_find_n(&ns->proc_table, pid);
|
||||
if (!pdata) {
|
||||
pdata = proc_create(ns, NULL, pid);
|
||||
}
|
||||
|
||||
// It's possible the process may have already generated the common port,
|
||||
// such as if the process calls exec.
|
||||
if(pdata->common_port_data != NULL)
|
||||
{
|
||||
client_t *c, *tmp;
|
||||
LIST_FOREACH_SAFE(c, &pdata->common_port_data->clients, client_pid_entry, tmp) {
|
||||
port_proc_cancel_client(c);
|
||||
}
|
||||
common_port_free(pdata->common_port_data);
|
||||
pdata->common_port_data = NULL;
|
||||
}
|
||||
|
||||
mach_port_options_t opts = {
|
||||
.flags = MPO_QLIMIT,
|
||||
.mpl.mpl_qlimit = 16,
|
||||
};
|
||||
|
||||
kstatus = mach_port_construct(mach_task_self(), &opts, 0, &port);
|
||||
assert(kstatus == KERN_SUCCESS);
|
||||
|
||||
// This right will be released in do_mach_notify_dead_name/port_free
|
||||
kstatus = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
|
||||
assert(kstatus == KERN_SUCCESS);
|
||||
|
||||
pdata->common_port_data = common_port_create(&global.notify_state, port);
|
||||
*out_port = port;
|
||||
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
kern_return_t __notify_server_register_common_port
|
||||
(
|
||||
mach_port_t server,
|
||||
caddr_t name,
|
||||
int token,
|
||||
audit_token_t audit
|
||||
)
|
||||
{
|
||||
client_t *c;
|
||||
uint64_t name_id, cid = 0;
|
||||
uint32_t status;
|
||||
uid_t uid = (uid_t)-1;
|
||||
gid_t gid = (gid_t)-1;
|
||||
pid_t pid = (pid_t)-1;
|
||||
|
||||
server_preflight(audit, token, &uid, &gid, &pid, &cid);
|
||||
|
||||
call_statistics.reg++;
|
||||
call_statistics.reg_common++;
|
||||
|
||||
log_message(ASL_LEVEL_DEBUG, "__notify_server_register_common_port %s %d %d\n", name, pid, token);
|
||||
|
||||
notify_state_t *ns = &global.notify_state;
|
||||
|
||||
proc_data_t *proc = _nc_table_find_n(&ns->proc_table, pid);
|
||||
if (!proc || !proc->common_port_data) {
|
||||
// Client doesn't have a common port set up
|
||||
log_message(ASL_LEVEL_DEBUG, "_notify_server_register_common_port FAILED %s %d %d\n", name, pid, token);
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
status = _notify_lib_register_common_port(ns, name, pid, token, uid, gid, &name_id);
|
||||
if (status != NOTIFY_STATUS_OK)
|
||||
{
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
c = _nc_table_find_64(&ns->client_table, cid);
|
||||
|
||||
if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, audit);
|
||||
|
||||
proc_add_client(proc, c, pid);
|
||||
LIST_INSERT_HEAD(&proc->common_port_data->clients, c, client_port_entry);
|
||||
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
kern_return_t __notify_server_register_mach_port_3
|
||||
(
|
||||
mach_port_t server,
|
||||
caddr_t name,
|
||||
int token,
|
||||
uint32_t *status,
|
||||
mach_port_t *out_port,
|
||||
audit_token_t audit
|
||||
)
|
||||
{
|
||||
mach_port_t port;
|
||||
kern_return_t kstatus;
|
||||
|
||||
*status = NOTIFY_STATUS_OK;
|
||||
*out_port = MACH_PORT_NULL;
|
||||
|
||||
mach_port_options_t opts = {
|
||||
.flags = MPO_QLIMIT,
|
||||
.mpl.mpl_qlimit = 16,
|
||||
};
|
||||
|
||||
kstatus = mach_port_construct(mach_task_self(), &opts, 0, &port);
|
||||
assert(kstatus == KERN_SUCCESS);
|
||||
|
||||
// This right will be released in do_mach_notify_dead_name/port_free
|
||||
kstatus = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
|
||||
assert(kstatus == KERN_SUCCESS);
|
||||
|
||||
*status = _notify_register_mach_port_helper(name, token, port, audit);
|
||||
|
||||
if (*status == NOTIFY_STATUS_OK)
|
||||
{
|
||||
*out_port = port;
|
||||
}
|
||||
else
|
||||
{
|
||||
mach_port_destruct(mach_task_self(), port, -1, 0);
|
||||
}
|
||||
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -43,11 +43,11 @@
|
||||
#include <TargetConditionals.h>
|
||||
#include <bsm/libbsm.h>
|
||||
#include <servers/bootstrap.h>
|
||||
#include <os/trace_private.h>
|
||||
|
||||
#include "pathwatch.h"
|
||||
#include "service.h"
|
||||
#include "pathwatch.h"
|
||||
#include "timer.h"
|
||||
|
||||
#include "notify_internal.h"
|
||||
#include "notify.h"
|
||||
@ -59,7 +59,7 @@
|
||||
#define CRSetCrashLogMessage(msg) /**/
|
||||
|
||||
#define forever for(;;)
|
||||
#define IndexNull -1
|
||||
#define IndexNull (unsigned int)~0
|
||||
|
||||
/* Compile flags */
|
||||
#define RUN_TIME_CHECKS
|
||||
@ -75,12 +75,6 @@ static char *_debug_log_path;
|
||||
#define DEBUG_LOG_PATH "/var/log/notifyd.log"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define N_NOTIFY_TYPES 6
|
||||
|
||||
static int notifyd_token;
|
||||
|
||||
static char *status_file = NULL;
|
||||
|
||||
struct global_s global;
|
||||
@ -111,12 +105,14 @@ notify_type_name(uint32_t t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case NOTIFY_TYPE_NONE: return "none ";
|
||||
case NOTIFY_TYPE_MEMORY: return "memory";
|
||||
case NOTIFY_TYPE_PLAIN: return "plain ";
|
||||
case NOTIFY_TYPE_PORT: return "port ";
|
||||
case NOTIFY_TYPE_FILE: return "file ";
|
||||
case NOTIFY_TYPE_SIGNAL: return "signal";
|
||||
case NOTIFY_TYPE_NONE: return "none ";
|
||||
case NOTIFY_TYPE_MEMORY: return "memory";
|
||||
case NOTIFY_TYPE_PLAIN: return "plain ";
|
||||
case NOTIFY_TYPE_PORT: return "port ";
|
||||
case NOTIFY_TYPE_FILE: return "file ";
|
||||
case NOTIFY_TYPE_SIGNAL: return "signal";
|
||||
case NOTIFY_TYPE_XPC_EVENT: return "event ";
|
||||
case NOTIFY_TYPE_COMMON_PORT: return "common";
|
||||
default: return "unknown";
|
||||
}
|
||||
|
||||
@ -136,18 +132,9 @@ fprint_client(FILE *f, client_t *c)
|
||||
fprintf(f, "token: %d\n", c->cid.token);
|
||||
fprintf(f, "lastval: %u\n", c->lastval);
|
||||
fprintf(f, "suspend_count: %u\n", c->suspend_count);
|
||||
fprintf(f, "type: %s\n", notify_type_name(c->state_and_type & NOTIFY_TYPE_MASK));
|
||||
switch(c->state_and_type & NOTIFY_TYPE_MASK)
|
||||
fprintf(f, "type: %s\n", notify_type_name(notify_get_type(c->state_and_type)));
|
||||
switch(notify_get_type(c->state_and_type))
|
||||
{
|
||||
case NOTIFY_TYPE_NONE:
|
||||
break;
|
||||
|
||||
case NOTIFY_TYPE_PLAIN:
|
||||
break;
|
||||
|
||||
case NOTIFY_TYPE_MEMORY:
|
||||
break;
|
||||
|
||||
case NOTIFY_TYPE_PORT:
|
||||
fprintf(f, "mach port: 0x%08x\n", c->deliver.port);
|
||||
break;
|
||||
@ -160,7 +147,19 @@ fprint_client(FILE *f, client_t *c)
|
||||
fprintf(f, "signal: %d\n", c->deliver.sig);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
case NOTIFY_TYPE_XPC_EVENT:
|
||||
fprintf(f, "xpc event: %llu\n", c->deliver.event_token);
|
||||
break;
|
||||
|
||||
case NOTIFY_TYPE_COMMON_PORT:
|
||||
fprintf(f, "common port\n");
|
||||
break;
|
||||
|
||||
case NOTIFY_TYPE_NONE:
|
||||
case NOTIFY_TYPE_PLAIN:
|
||||
case NOTIFY_TYPE_MEMORY:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,7 +172,7 @@ fprint_quick_client(FILE *f, client_t *c)
|
||||
fprintf(f, "%llu,%d,%d,%u,%u,%u,", c->cid.hash_key, c->cid.pid, c->cid.token,
|
||||
c->lastval, c->suspend_count, 0);
|
||||
|
||||
switch(c->state_and_type & NOTIFY_TYPE_MASK)
|
||||
switch(notify_get_type(c->state_and_type))
|
||||
{
|
||||
case NOTIFY_TYPE_PORT:
|
||||
fprintf(f, "port,0x%08x\n", c->deliver.port);
|
||||
@ -191,6 +190,14 @@ fprint_quick_client(FILE *f, client_t *c)
|
||||
fprintf(f, "check,0\n");
|
||||
break;
|
||||
|
||||
case NOTIFY_TYPE_XPC_EVENT:
|
||||
fprintf(f, "event,%llu\n", c->deliver.event_token);
|
||||
break;
|
||||
|
||||
case NOTIFY_TYPE_COMMON_PORT:
|
||||
fprintf(f, "common-port\n");
|
||||
break;
|
||||
|
||||
case NOTIFY_TYPE_NONE:
|
||||
case NOTIFY_TYPE_PLAIN:
|
||||
default:
|
||||
@ -215,7 +222,7 @@ fprint_quick_name_info(FILE *f, name_info_t *n)
|
||||
fprintf(f, "name:%s\n", n->name);
|
||||
fprintf(f, "info:%llu,%u,%u,%03x,%u,%u,%u,", n->name_id, n->uid, n->gid, n->access, n->refcount, n->postcount,
|
||||
n->last_hour_postcount);
|
||||
if (n->slot == -1)
|
||||
if (n->slot == SLOT_NONE)
|
||||
{
|
||||
fprintf(f, "-1,");
|
||||
}
|
||||
@ -257,11 +264,11 @@ fprint_name_info(FILE *f, const char *name, name_info_t *n, pid_t *max_pid)
|
||||
fprintf(f, "refcount: %u\n", n->refcount);
|
||||
fprintf(f, "postcount: %u\n", n->postcount);
|
||||
fprintf(f, "last hour postcount: %u\n", n->last_hour_postcount);
|
||||
if (n->slot == -1) fprintf(f, "slot: -unassigned-");
|
||||
if (n->slot == SLOT_NONE) fprintf(f, "slot: -unassigned-");
|
||||
else
|
||||
{
|
||||
fprintf(f, "slot: %u", n->slot);
|
||||
if (global.shared_memory_refcount[n->slot] != -1)
|
||||
if (global.shared_memory_refcount[n->slot] != SLOT_NONE)
|
||||
fprintf(f, " = %u (%u)", global.shared_memory_base[n->slot], global.shared_memory_refcount[n->slot]);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
@ -272,20 +279,22 @@ fprint_name_info(FILE *f, const char *name, name_info_t *n, pid_t *max_pid)
|
||||
|
||||
LIST_FOREACH(c, &n->subscriptions, client_subscription_entry)
|
||||
{
|
||||
if ((c->cid.pid != (pid_t)-1) && (c->cid.pid > *max_pid)) *max_pid = c->cid.pid;
|
||||
if ((c->cid.pid != (uint32_t)~0) && (c->cid.pid > (uint32_t)*max_pid)) *max_pid = (pid_t)c->cid.pid;
|
||||
|
||||
switch (c->state_and_type & NOTIFY_TYPE_MASK)
|
||||
switch (notify_get_type(c->state_and_type))
|
||||
{
|
||||
case NOTIFY_TYPE_MEMORY: reg[1]++; break;
|
||||
case NOTIFY_TYPE_PLAIN: reg[2]++; break;
|
||||
case NOTIFY_TYPE_PORT: reg[3]++; break;
|
||||
case NOTIFY_TYPE_FILE: reg[4]++; break;
|
||||
case NOTIFY_TYPE_SIGNAL: reg[5]++; break;
|
||||
case NOTIFY_TYPE_XPC_EVENT: reg[6]++; break;
|
||||
case NOTIFY_TYPE_COMMON_PORT: reg[7]++; break;
|
||||
default: reg[0]++;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f, "types: none %u memory %u plain %u port %u file %u signal %u\n", reg[0], reg[1], reg[2], reg[3], reg[4], reg[5]);
|
||||
fprintf(f, "types: none %u memory %u plain %u port %u file %u signal %u event %u common %u\n", reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7]);
|
||||
|
||||
LIST_FOREACH(c, &n->subscriptions, client_subscription_entry)
|
||||
{
|
||||
@ -297,7 +306,7 @@ fprint_name_info(FILE *f, const char *name, name_info_t *n, pid_t *max_pid)
|
||||
static void
|
||||
fprint_quick_status(FILE *f)
|
||||
{
|
||||
int32_t i;
|
||||
uint32_t i;
|
||||
|
||||
fprintf(f, "--- GLOBALS ---\n");
|
||||
fprintf(f, "%u slots (current id %u)\n", global.nslots, global.slot_id);
|
||||
@ -317,6 +326,8 @@ fprint_quick_status(FILE *f)
|
||||
fprintf(f, " signal %llu\n", call_statistics.reg_signal);
|
||||
fprintf(f, " file %llu\n", call_statistics.reg_file);
|
||||
fprintf(f, " port %llu\n", call_statistics.reg_port);
|
||||
fprintf(f, " event %llu\n", call_statistics.reg_xpc_event);
|
||||
fprintf(f, " common %llu\n", call_statistics.reg_common);
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "check %llu\n", call_statistics.check);
|
||||
fprintf(f, "cancel %llu\n", call_statistics.cancel);
|
||||
@ -345,7 +356,6 @@ fprint_quick_status(FILE *f)
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "monitor %llu\n", call_statistics.monitor_file);
|
||||
fprintf(f, "svc_path %llu\n", call_statistics.service_path);
|
||||
fprintf(f, "svc_timer %llu\n", call_statistics.service_timer);
|
||||
|
||||
{
|
||||
char buf[128];
|
||||
@ -385,17 +395,17 @@ fprint_quick_status(FILE *f)
|
||||
fprintf(f, "\n");
|
||||
|
||||
fprintf(f, "--- PUBLIC SERVICE ---\n");
|
||||
|
||||
_nc_table_foreach(&global.notify_state.name_table, ^bool(void *_n) {
|
||||
name_info_t *n = _n;
|
||||
|
||||
_nc_table_foreach_64(&global.notify_state.client_table, ^bool(void *_c){
|
||||
client_t *c = _c;
|
||||
name_info_t *n = c->name_info;
|
||||
svc_info_t *info;
|
||||
path_node_t *node;
|
||||
timer_t *timer;
|
||||
|
||||
if (n->private == NULL) return true;
|
||||
|
||||
info = (svc_info_t *)n->private;
|
||||
|
||||
info = service_info_get(c->service_index);
|
||||
|
||||
if (info == NULL) return true;
|
||||
|
||||
if (info->type == 0)
|
||||
{
|
||||
fprintf(f, "Null service: %s\n", n->name);
|
||||
@ -405,28 +415,6 @@ fprint_quick_status(FILE *f)
|
||||
node = (path_node_t *)info->private;
|
||||
fprintf(f, "Path Service: %s <- %s\n", n->name, node->path);
|
||||
}
|
||||
else if (info->type == SERVICE_TYPE_TIMER_PUBLIC)
|
||||
{
|
||||
timer = (timer_t *)info->private;
|
||||
switch (timer->type)
|
||||
{
|
||||
case TIME_EVENT_ONESHOT:
|
||||
{
|
||||
fprintf(f, "Time Service: %s <- Oneshot %llu\n", n->name, timer->start);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CLOCK:
|
||||
{
|
||||
fprintf(f, "Time Service: %s <- Clock start %lld freq %u end %lld\n", n->name, timer->start, timer->freq, timer->end);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CAL:
|
||||
{
|
||||
fprintf(f, "Time Service: %s <- Calendar start %lld freq %u end %lld day %d\n", n->name, timer->start, timer->freq, timer->end, timer->day);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(f, "Unknown service: %s (%u)\n", n->name, info->type);
|
||||
@ -443,7 +431,6 @@ fprint_quick_status(FILE *f)
|
||||
svc_info_t *info;
|
||||
name_info_t *n;
|
||||
path_node_t *node;
|
||||
timer_t *timer;
|
||||
|
||||
if (c->service_index == 0) return true;
|
||||
|
||||
@ -459,28 +446,6 @@ fprint_quick_status(FILE *f)
|
||||
node = (path_node_t *)info->private;
|
||||
fprintf(f, "PID %u Path Service: %s <- %s\n", c->cid.pid, n->name, node->path);
|
||||
}
|
||||
else if (info->type == SERVICE_TYPE_TIMER_PRIVATE)
|
||||
{
|
||||
timer = (timer_t *)info->private;
|
||||
switch (timer->type)
|
||||
{
|
||||
case TIME_EVENT_ONESHOT:
|
||||
{
|
||||
fprintf(f, "PID %u Time Service: %s <- Oneshot %"PRId64"\n", c->cid.pid, n->name, timer->start);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CLOCK:
|
||||
{
|
||||
fprintf(f, "PID %u Time Service: %s <- Clock start %"PRId64" freq %"PRIu32" end %"PRId64"\n", c->cid.pid, n->name, timer->start, timer->freq, timer->end);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CAL:
|
||||
{
|
||||
fprintf(f, "PID %u Time Service: %s <- Calendar start %"PRId64" freq %"PRIu32" end %"PRId64" day %"PRId32"\n", c->cid.pid, n->name, timer->start, timer->freq, timer->end, timer->day);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
@ -493,7 +458,7 @@ static void
|
||||
fprint_status(FILE *f)
|
||||
{
|
||||
__block pid_t pid, max_pid;
|
||||
int32_t i;
|
||||
uint32_t i;
|
||||
|
||||
max_pid = 0;
|
||||
|
||||
@ -515,6 +480,8 @@ fprint_status(FILE *f)
|
||||
fprintf(f, " signal %llu\n", call_statistics.reg_signal);
|
||||
fprintf(f, " file %llu\n", call_statistics.reg_file);
|
||||
fprintf(f, " port %llu\n", call_statistics.reg_port);
|
||||
fprintf(f, " event %llu\n", call_statistics.reg_xpc_event);
|
||||
fprintf(f, " common %llu\n", call_statistics.reg_common);
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "check %llu\n", call_statistics.check);
|
||||
fprintf(f, "cancel %llu\n", call_statistics.cancel);
|
||||
@ -543,7 +510,6 @@ fprint_status(FILE *f)
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "monitor %llu\n", call_statistics.monitor_file);
|
||||
fprintf(f, "svc_path %llu\n", call_statistics.service_path);
|
||||
fprintf(f, "svc_timer %llu\n", call_statistics.service_timer);
|
||||
|
||||
|
||||
{
|
||||
@ -595,15 +561,15 @@ fprint_status(FILE *f)
|
||||
|
||||
fprintf(f, "--- PUBLIC SERVICE ---\n");
|
||||
|
||||
_nc_table_foreach(&global.notify_state.name_table, ^bool(void *_n) {
|
||||
name_info_t *n = _n;
|
||||
_nc_table_foreach_64(&global.notify_state.client_table, ^bool(void *_c){
|
||||
client_t *c = _c;
|
||||
name_info_t *n = c->name_info;
|
||||
svc_info_t *info;
|
||||
path_node_t *node;
|
||||
timer_t *timer;
|
||||
|
||||
if (n->private == NULL) return true;
|
||||
|
||||
info = (svc_info_t *)n->private;
|
||||
info = service_info_get(c->service_index);
|
||||
|
||||
if (info == NULL) return true;
|
||||
|
||||
if (info->type == 0)
|
||||
{
|
||||
@ -614,28 +580,6 @@ fprint_status(FILE *f)
|
||||
node = (path_node_t *)info->private;
|
||||
fprintf(f, "Path Service: %s <- %s\n", n->name, node->path);
|
||||
}
|
||||
else if (info->type == SERVICE_TYPE_TIMER_PUBLIC)
|
||||
{
|
||||
timer = (timer_t *)info->private;
|
||||
switch (timer->type)
|
||||
{
|
||||
case TIME_EVENT_ONESHOT:
|
||||
{
|
||||
fprintf(f, "Time Service: %s <- Oneshot %llu\n", n->name, timer->start);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CLOCK:
|
||||
{
|
||||
fprintf(f, "Time Service: %s <- Clock start %lld freq %u end %lld\n", n->name, timer->start, timer->freq, timer->end);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CAL:
|
||||
{
|
||||
fprintf(f, "Time Service: %s <- Calendar start %lld freq %u end %lld day %d\n", n->name, timer->start, timer->freq, timer->end, timer->day);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(f, "Unknown service: %s (%u)\n", n->name, info->type);
|
||||
@ -653,7 +597,6 @@ fprint_status(FILE *f)
|
||||
name_info_t *n;
|
||||
svc_info_t *info;
|
||||
path_node_t *node;
|
||||
timer_t *timer;
|
||||
|
||||
if (c->service_index == 0) return true;
|
||||
|
||||
@ -669,28 +612,6 @@ fprint_status(FILE *f)
|
||||
node = (path_node_t *)info->private;
|
||||
fprintf(f, "PID %u Path Service: %s <- %s\n", c->cid.pid, n->name, node->path);
|
||||
}
|
||||
else if (info->type == SERVICE_TYPE_TIMER_PRIVATE)
|
||||
{
|
||||
timer = (timer_t *)info->private;
|
||||
switch (timer->type)
|
||||
{
|
||||
case TIME_EVENT_ONESHOT:
|
||||
{
|
||||
fprintf(f, "PID %u Time Service: %s <- Oneshot %"PRId64"\n", c->cid.pid, n->name, timer->start);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CLOCK:
|
||||
{
|
||||
fprintf(f, "PID %u Time Service: %s <- Clock start %"PRId64" freq %"PRIu32" end %"PRId64"\n", c->cid.pid, n->name, timer->start, timer->freq, timer->end);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CAL:
|
||||
{
|
||||
fprintf(f, "PID %u Time Service: %s <- Calendar start %"PRId64" freq %"PRIu32" end %"PRId64" day %"PRId32"\n", c->cid.pid, n->name, timer->start, timer->freq, timer->end, timer->day);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
@ -700,7 +621,7 @@ fprint_status(FILE *f)
|
||||
fprintf(f, "--- PROCESSES ---\n");
|
||||
for (pid = 0; pid <= max_pid; pid++)
|
||||
{
|
||||
int mem_count, plain_count, file_count, port_count, sig_count;
|
||||
int mem_count, plain_count, file_count, port_count, sig_count, event_count, common_port_count;
|
||||
proc_data_t *pdata;
|
||||
client_t *c;
|
||||
|
||||
@ -712,9 +633,11 @@ fprint_status(FILE *f)
|
||||
file_count = 0;
|
||||
port_count = 0;
|
||||
sig_count = 0;
|
||||
event_count = 0;
|
||||
common_port_count = 0;
|
||||
|
||||
LIST_FOREACH(c, &pdata->clients, client_pid_entry) {
|
||||
switch(c->state_and_type & NOTIFY_TYPE_MASK) {
|
||||
switch(notify_get_type(c->state_and_type)) {
|
||||
case NOTIFY_TYPE_NONE:
|
||||
break;
|
||||
|
||||
@ -738,6 +661,14 @@ fprint_status(FILE *f)
|
||||
sig_count++;
|
||||
break;
|
||||
|
||||
case NOTIFY_TYPE_XPC_EVENT:
|
||||
event_count++;
|
||||
break;
|
||||
|
||||
case NOTIFY_TYPE_COMMON_PORT:
|
||||
common_port_count++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -745,10 +676,10 @@ fprint_status(FILE *f)
|
||||
|
||||
fprintf(f, "pid: %u ", pid);
|
||||
|
||||
fprintf(f, "memory %u plain %u port %u file %u signal %u\n",
|
||||
mem_count, plain_count, port_count, file_count, sig_count);
|
||||
fprintf(f, "memory %u plain %u port %u file %u signal %u event %u common %u\n",
|
||||
mem_count, plain_count, port_count, file_count, sig_count, event_count, common_port_count);
|
||||
LIST_FOREACH(c, &pdata->clients, client_pid_entry) {
|
||||
fprintf(f, " %s: %s\n", notify_type_name(c->state_and_type & NOTIFY_TYPE_MASK), c->name_info->name);
|
||||
fprintf(f, " %s: %s\n", notify_type_name(notify_get_type(c->state_and_type)), c->name_info->name);
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
@ -887,7 +818,7 @@ daemon_post_client(uint64_t cid)
|
||||
c = _nc_table_find_64(&global.notify_state.client_table, cid);
|
||||
if (c == NULL) return;
|
||||
|
||||
if ((c->state_and_type & NOTIFY_TYPE_MEMORY) && (c->name_info != NULL) && (c->name_info->slot != (uint32_t)-1))
|
||||
if (notify_is_type(c->state_and_type, NOTIFY_TYPE_MEMORY) && (c->name_info != NULL) && (c->name_info->slot != (uint32_t)-1))
|
||||
{
|
||||
global.shared_memory_base[c->name_info->slot]++;
|
||||
}
|
||||
@ -952,7 +883,7 @@ string_list_free(char **l)
|
||||
static char **
|
||||
string_insert(char *s, char **l, unsigned int x)
|
||||
{
|
||||
int i, len;
|
||||
unsigned int i, len;
|
||||
|
||||
if (s == NULL) return l;
|
||||
if (l == NULL)
|
||||
@ -1078,7 +1009,7 @@ init_config(void)
|
||||
val64 <<= 32;
|
||||
val64 |= NOTIFY_IPC_VERSION;
|
||||
|
||||
_notify_lib_register_plain(&global.notify_state, NOTIFY_IPC_VERSION_NAME, -1, notifyd_token++, -1, 0, 0, &nid);
|
||||
_notify_lib_register_plain(&global.notify_state, NOTIFY_IPC_VERSION_NAME, -1, global.next_no_client_token++, -1, 0, 0, &nid);
|
||||
_notify_lib_set_state(&global.notify_state, nid, val64, 0, 0);
|
||||
|
||||
/* Check config file */
|
||||
@ -1109,7 +1040,11 @@ init_config(void)
|
||||
line[strlen(line) - 1] = '\0';
|
||||
args = explode(line, "\t ");
|
||||
argslen = string_list_length(args);
|
||||
if (argslen == 0) continue;
|
||||
if (argslen == 0)
|
||||
{
|
||||
string_list_free(args);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcasecmp(args[0], "monitor")) {
|
||||
if (argslen < 3)
|
||||
@ -1117,24 +1052,12 @@ init_config(void)
|
||||
string_list_free(args);
|
||||
continue;
|
||||
}
|
||||
_notify_lib_register_plain(&global.notify_state, args[1], -1, notifyd_token++, -1, 0, 0, &nid);
|
||||
_notify_lib_register_plain(&global.notify_state, args[1], -1, global.next_no_client_token++, -1, 0, 0, &nid);
|
||||
|
||||
dispatch_async(global.workloop, ^{
|
||||
service_open_path(args[1], args[2], 0, 0);
|
||||
string_list_free(args);
|
||||
});
|
||||
} else if (!strcasecmp(args[0], "timer")) {
|
||||
if (argslen < 3)
|
||||
{
|
||||
string_list_free(args);
|
||||
continue;
|
||||
}
|
||||
_notify_lib_register_plain(&global.notify_state, args[1], -1, notifyd_token++, -1, 0, 0, &nid);
|
||||
|
||||
dispatch_async(global.workloop, ^{
|
||||
service_open_timer(args[1], args[2]);
|
||||
string_list_free(args);
|
||||
});
|
||||
} else if (!strcasecmp(args[0], "set")) {
|
||||
if (argslen == 1 || argslen > 3)
|
||||
{
|
||||
@ -1142,7 +1065,7 @@ init_config(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
_notify_lib_register_plain(&global.notify_state, args[1], -1, notifyd_token++, -1, 0, 0, &nid);
|
||||
_notify_lib_register_plain(&global.notify_state, args[1], -1, global.next_no_client_token++, -1, 0, 0, &nid);
|
||||
if (argslen == 3)
|
||||
{
|
||||
val64 = atoll(args[2]);
|
||||
@ -1172,6 +1095,8 @@ init_config(void)
|
||||
} else if (!strcasecmp(args[0], "quit")) {
|
||||
string_list_free(args);
|
||||
break;
|
||||
} else {
|
||||
string_list_free(args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1290,7 +1215,8 @@ main(int argc, const char *argv[])
|
||||
{
|
||||
const char *service_name;
|
||||
const char *shm_name;
|
||||
uint32_t i, status;
|
||||
int i;
|
||||
uint32_t status;
|
||||
struct rlimit rlim;
|
||||
kern_return_t kr;
|
||||
|
||||
@ -1303,6 +1229,7 @@ main(int argc, const char *argv[])
|
||||
shm_name = SHM_ID;
|
||||
|
||||
notify_set_options(NOTIFY_OPT_DISABLE);
|
||||
os_trace_set_mode(OS_TRACE_MODE_DISABLE);
|
||||
|
||||
/* remove limit of number of file descriptors */
|
||||
rlim.rlim_max = RLIM_INFINITY;
|
||||
@ -1319,6 +1246,7 @@ main(int argc, const char *argv[])
|
||||
|
||||
global.nslots = getpagesize() / sizeof(uint32_t);
|
||||
_notify_lib_notify_state_init(&global.notify_state, NOTIFY_STATE_ENABLE_RESEND);
|
||||
global.next_no_client_token = 1;
|
||||
|
||||
global.log_cutoff = ASL_LEVEL_ERR;
|
||||
global.log_path = strdup(DEBUG_LOG_PATH);
|
||||
@ -1375,15 +1303,14 @@ main(int argc, const char *argv[])
|
||||
mach_port_options_t opts = {
|
||||
.flags = MPO_STRICT | MPO_CONTEXT_AS_GUARD,
|
||||
};
|
||||
kr = mach_port_construct(current_task(), &opts, &global, &global.mach_notify_port);
|
||||
kr = mach_port_construct(current_task(), &opts, (mach_port_context_t)&global, &global.mach_notify_port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
NOTIFY_INTERNAL_CRASH(kr, "Unable to allocate Mach notification port");
|
||||
}
|
||||
global.mach_notifs_channel = dispatch_mach_create_f("com.apple.notifyd.mach-notifs",
|
||||
global.workloop, NULL, mach_notifs_handle);
|
||||
dispatch_set_qos_class_fallback(global.mach_notifs_channel, QOS_CLASS_USER_INITIATED);
|
||||
dispatch_mach_connect(global.mach_notifs_channel, global.mach_notify_port,
|
||||
MACH_PORT_NULL, NULL);
|
||||
// dispatch_mach_connect happens in XPC_EVENT_PUBLISHER_ACTION_INITIAL_BARRIER
|
||||
|
||||
global.mach_channel = dispatch_mach_create_f("com.apple.notifyd.channel",
|
||||
global.workloop, NULL, notifyd_mach_channel_handler);
|
||||
@ -1393,7 +1320,33 @@ main(int argc, const char *argv[])
|
||||
#else
|
||||
dispatch_set_qos_class_fallback(global.mach_channel, QOS_CLASS_BACKGROUND);
|
||||
#endif
|
||||
dispatch_mach_connect(global.mach_channel, global.server_port, MACH_PORT_NULL, NULL);
|
||||
// dispatch_mach_connect happens in XPC_EVENT_PUBLISHER_ACTION_INITIAL_BARRIER
|
||||
|
||||
xpc_event_publisher_t publisher = xpc_event_publisher_create("com.apple.notifyd.matching", global.workloop);
|
||||
global.notify_state.event_publisher = publisher;
|
||||
xpc_event_publisher_set_handler(publisher,
|
||||
^(xpc_event_publisher_action_t action, uint64_t event_token, xpc_object_t descriptor) {
|
||||
switch (action) {
|
||||
case XPC_EVENT_PUBLISHER_ACTION_ADD:
|
||||
notifyd_matching_register(event_token, descriptor);
|
||||
break;
|
||||
case XPC_EVENT_PUBLISHER_ACTION_REMOVE:
|
||||
notifyd_matching_unregister(event_token);
|
||||
break;
|
||||
case XPC_EVENT_PUBLISHER_ACTION_INITIAL_BARRIER:
|
||||
dispatch_mach_connect(
|
||||
global.mach_notifs_channel, global.mach_notify_port,
|
||||
MACH_PORT_NULL, NULL);
|
||||
dispatch_mach_connect(
|
||||
global.mach_channel, global.server_port,
|
||||
MACH_PORT_NULL, NULL);
|
||||
break;
|
||||
}
|
||||
});
|
||||
xpc_event_publisher_set_error_handler(publisher, ^(int error) {
|
||||
NOTIFY_INTERNAL_CRASH(error, "Event publisher error");
|
||||
});
|
||||
xpc_event_publisher_activate(publisher);
|
||||
|
||||
/* Set up SIGUSR1 */
|
||||
global.sig_usr1_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL,
|
||||
|
@ -58,8 +58,9 @@ struct global_s
|
||||
uint32_t *shared_memory_base;
|
||||
uint32_t *shared_memory_refcount;
|
||||
uint32_t *last_shm_base;
|
||||
uint32_t log_cutoff;
|
||||
int log_cutoff;
|
||||
uint32_t log_default;
|
||||
uint32_t next_no_client_token;
|
||||
uint16_t service_info_count;
|
||||
char *log_path;
|
||||
};
|
||||
@ -79,6 +80,8 @@ struct call_statistics_s
|
||||
uint64_t reg_signal;
|
||||
uint64_t reg_file;
|
||||
uint64_t reg_port;
|
||||
uint64_t reg_xpc_event;
|
||||
uint64_t reg_common;
|
||||
uint64_t cancel;
|
||||
uint64_t suspend;
|
||||
uint64_t resume;
|
||||
@ -96,7 +99,6 @@ struct call_statistics_s
|
||||
uint64_t set_owner;
|
||||
uint64_t set_access;
|
||||
uint64_t monitor_file;
|
||||
uint64_t service_timer;
|
||||
uint64_t service_path;
|
||||
uint64_t cleanup;
|
||||
uint64_t regenerate;
|
||||
@ -114,6 +116,9 @@ extern void dump_status(uint32_t level, int fd);
|
||||
extern bool has_entitlement(audit_token_t audit, const char *entitlement);
|
||||
extern bool has_root_entitlement(audit_token_t audit);
|
||||
|
||||
void notifyd_matching_register(uint64_t event_token, xpc_object_t descriptor);
|
||||
void notifyd_matching_unregister(uint64_t event_token);
|
||||
|
||||
dispatch_queue_t get_notifyd_workloop(void);
|
||||
|
||||
#endif /* _NOTIFY_DAEMON_H_ */
|
||||
|
@ -173,7 +173,6 @@ _path_stat(const char *path, int link, uid_t uid, gid_t gid)
|
||||
pthread_setugid_np(uid, gid);
|
||||
|
||||
/* stat the file */
|
||||
stat_status = -1;
|
||||
if (link != 0)
|
||||
{
|
||||
stat_status = lstat(path, &sb);
|
||||
@ -352,7 +351,7 @@ _vnode_event(vnode_t *vnode)
|
||||
if (vnode == NULL) return;
|
||||
if ((vnode->src != NULL) && (dispatch_source_testcancel(vnode->src))) return;
|
||||
|
||||
ulf = dispatch_source_get_data(vnode->src);
|
||||
ulf = vnode->src ? dispatch_source_get_data(vnode->src) : 0;
|
||||
flags = (uint32_t)ulf;
|
||||
|
||||
memset(&sb, 0, sizeof(struct stat));
|
||||
@ -746,7 +745,9 @@ _path_node_init(const char *path)
|
||||
{
|
||||
name = malloc(len + 1);
|
||||
assert(name != NULL);
|
||||
strncpy(name, start, len);
|
||||
if (start != NULL) {
|
||||
strncpy(name, start, len);
|
||||
}
|
||||
name[len] = '\0';
|
||||
}
|
||||
|
||||
@ -847,7 +848,9 @@ _path_node_update(path_node_t *pnode, uint32_t flags, vnode_t *vnode)
|
||||
{
|
||||
/* suspend pnode->src, and fire it after PNODE_COALESCE_TIME */
|
||||
pnode->flags |= PATH_SRC_SUSPENDED;
|
||||
dispatch_suspend(pnode->src);
|
||||
if (pnode->src) {
|
||||
dispatch_suspend(pnode->src);
|
||||
}
|
||||
|
||||
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, PNODE_COALESCE_TIME);
|
||||
_path_node_retain(pnode);
|
||||
@ -859,7 +862,9 @@ _path_node_update(path_node_t *pnode, uint32_t flags, vnode_t *vnode)
|
||||
});
|
||||
}
|
||||
|
||||
dispatch_source_merge_data(pnode->src, data);
|
||||
if (pnode->src) {
|
||||
dispatch_source_merge_data(pnode->src, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -935,8 +940,6 @@ path_node_create(const char *path, audit_token_t audit, bool is_notifyd, uint32_
|
||||
|
||||
_path_node_update(pnode, 0, NULL);
|
||||
|
||||
dispatch_retain(queue);
|
||||
|
||||
pnode->src = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_OR, 0, 0, queue);
|
||||
pnode->flags = mask & PATH_NODE_ALL;
|
||||
if (is_notifyd)
|
||||
|
@ -31,13 +31,10 @@
|
||||
#include "notifyd.h"
|
||||
#include "service.h"
|
||||
#include "pathwatch.h"
|
||||
#include "timer.h"
|
||||
#include "notify_internal.h"
|
||||
|
||||
#define NOTIFY_PATH_SERVICE "path:"
|
||||
#define NOTIFY_PATH_SERVICE_LEN 5
|
||||
#define NOTIFY_TIMER_SERVICE "timer:"
|
||||
#define NOTIFY_TIMER_SERVICE_LEN 6
|
||||
|
||||
/* Libinfo global */
|
||||
extern uint32_t gL1CacheEnabled;
|
||||
@ -50,7 +47,6 @@ service_type(const char *name)
|
||||
len = SERVICE_PREFIX_LEN;
|
||||
if (strncmp(name, SERVICE_PREFIX, len)) return SERVICE_TYPE_NONE;
|
||||
else if (!strncmp(name + len, NOTIFY_PATH_SERVICE, NOTIFY_PATH_SERVICE_LEN)) return SERVICE_TYPE_PATH_PRIVATE;
|
||||
else if (!strncmp(name + len, NOTIFY_TIMER_SERVICE, NOTIFY_TIMER_SERVICE_LEN)) return SERVICE_TYPE_TIMER_PRIVATE;
|
||||
|
||||
return SERVICE_TYPE_NONE;
|
||||
}
|
||||
@ -75,7 +71,6 @@ int
|
||||
service_open_path(const char *name, const char *path, uid_t uid, gid_t gid)
|
||||
{
|
||||
name_info_t *n;
|
||||
svc_info_t *info;
|
||||
path_node_t *node;
|
||||
|
||||
call_statistics.service_path++;
|
||||
@ -85,20 +80,6 @@ service_open_path(const char *name, const char *path, uid_t uid, gid_t gid)
|
||||
n = _nc_table_find(&global.notify_state.name_table, name);
|
||||
if (n == NULL) return NOTIFY_STATUS_INVALID_NAME;
|
||||
|
||||
if (n->private != NULL)
|
||||
{
|
||||
/* a notify key may only have one service associated with it */
|
||||
info = (svc_info_t *)n->private;
|
||||
if (info->type != SERVICE_TYPE_PATH_PUBLIC) return NOTIFY_STATUS_INVALID_REQUEST;
|
||||
|
||||
/* the client must be asking for the same path that is being monitored */
|
||||
node = (path_node_t *)info->private;
|
||||
if (strcmp(path, node->path)) return NOTIFY_STATUS_INVALID_REQUEST;
|
||||
|
||||
/* the name is already getting notifications for this path */
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
{
|
||||
audit_token_t audit;
|
||||
memset(&audit, 0, sizeof(audit_token_t));
|
||||
@ -109,13 +90,6 @@ service_open_path(const char *name, const char *path, uid_t uid, gid_t gid)
|
||||
|
||||
node->contextp = strdup(name);
|
||||
|
||||
info = (svc_info_t *)calloc(1, sizeof(svc_info_t));
|
||||
assert(info != NULL);
|
||||
|
||||
info->type = SERVICE_TYPE_PATH_PUBLIC;
|
||||
info->private = node;
|
||||
n->private = info;
|
||||
|
||||
dispatch_source_set_event_handler(node->src, ^{
|
||||
daemon_post((const char *)node->contextp, uid, gid);
|
||||
});
|
||||
@ -233,261 +207,6 @@ service_open_path_private(const char *name, client_t *c, const char *path, audit
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
/* format: [+]nnnn[s|m|h|d] */
|
||||
static int
|
||||
parse_single_arg(const char *arg, int relative_ok, time_t *t)
|
||||
{
|
||||
const char *p, *q;
|
||||
time_t now, val;
|
||||
|
||||
if (arg == NULL) return -1;
|
||||
p = arg;
|
||||
|
||||
now = 0;
|
||||
|
||||
if ((relative_ok != 0) && ((*p == '+') || (*p == '-')))
|
||||
{
|
||||
p++;
|
||||
now = time(NULL);
|
||||
}
|
||||
|
||||
if ((*p < '0') || (*p > '9')) return -1;
|
||||
|
||||
q = strchr(p, '.');
|
||||
if (q != NULL) q--;
|
||||
else q = arg + strlen(arg) - 1;
|
||||
|
||||
#ifdef __LP64__
|
||||
val = (time_t)atoll(p);
|
||||
#else
|
||||
val = (time_t)atoi(p);
|
||||
#endif
|
||||
|
||||
if ((*q >= '0') && (*q <= '9'))
|
||||
{}
|
||||
else if (*q == 's')
|
||||
{}
|
||||
else if (*q == 'm')
|
||||
{
|
||||
val *= 60;
|
||||
}
|
||||
else if (*q == 'h')
|
||||
{
|
||||
val *= 3600;
|
||||
}
|
||||
else if (*q == 'd')
|
||||
{
|
||||
val *= 86400;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*arg == '-') *t = now - val;
|
||||
else *t = now + val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
parse_timer_args(const char *args, time_t *s, time_t *f, time_t *e, int32_t *d)
|
||||
{
|
||||
char *p;
|
||||
uint32_t t;
|
||||
|
||||
if (args == NULL) return TIME_EVENT_NONE;
|
||||
|
||||
/* first arg is start time */
|
||||
if (parse_single_arg(args, 1, s) != 0) return TIME_EVENT_NONE;
|
||||
t = TIME_EVENT_ONESHOT;
|
||||
|
||||
p = strchr(args, '.');
|
||||
if (p != NULL)
|
||||
{
|
||||
/* second arg is frequency */
|
||||
p++;
|
||||
if (parse_single_arg(p, 0, f) != 0) return TIME_EVENT_NONE;
|
||||
t = TIME_EVENT_CLOCK;
|
||||
|
||||
p = strchr(p, '.');
|
||||
if (p != NULL)
|
||||
{
|
||||
/* third arg is end time */
|
||||
p++;
|
||||
if (parse_single_arg(args, 1, e) != 0) return TIME_EVENT_NONE;
|
||||
|
||||
p = strchr(p, '.');
|
||||
if (p != NULL)
|
||||
{
|
||||
/* fourth arg is day number */
|
||||
p++;
|
||||
*d = atoi(p);
|
||||
t = TIME_EVENT_CAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (f == 0) t = TIME_EVENT_ONESHOT;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
int
|
||||
service_open_timer(const char *name, const char *args)
|
||||
{
|
||||
uint32_t t;
|
||||
time_t s, f, e;
|
||||
int32_t d;
|
||||
name_info_t *n;
|
||||
svc_info_t *info;
|
||||
timer_t *timer;
|
||||
|
||||
call_statistics.service_timer++;
|
||||
|
||||
n = _nc_table_find(&global.notify_state.name_table, name);
|
||||
if (n == NULL) return NOTIFY_STATUS_INVALID_NAME;
|
||||
|
||||
s = f = e = 0;
|
||||
d = 0;
|
||||
|
||||
t = parse_timer_args(args, &s, &f, &e, &d);
|
||||
if (t == TIME_EVENT_NONE) return NOTIFY_STATUS_INVALID_REQUEST;
|
||||
|
||||
if (n->private != NULL)
|
||||
{
|
||||
/* a notify key may only have one service associated with it */
|
||||
info = (svc_info_t *)n->private;
|
||||
if (info->type != SERVICE_TYPE_TIMER_PUBLIC) return NOTIFY_STATUS_INVALID_REQUEST;
|
||||
|
||||
/* the client must be asking for the same timer that is active */
|
||||
timer = (timer_t *)info->private;
|
||||
if ((timer->type != t) || (timer->start != s) || (timer->freq != f) || (timer->end != e) || (timer->day != d)) return NOTIFY_STATUS_INVALID_REQUEST;
|
||||
|
||||
/* the name is already getting notifications for this timer */
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
switch (t)
|
||||
{
|
||||
case TIME_EVENT_ONESHOT:
|
||||
{
|
||||
timer = timer_oneshot(s, global.workloop);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CLOCK:
|
||||
{
|
||||
timer = timer_clock(s, f, e, global.workloop);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CAL:
|
||||
{
|
||||
timer = timer_calendar(s, f, e, d, global.workloop);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return NOTIFY_STATUS_INVALID_TIME_EVENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (timer == NULL) return NOTIFY_STATUS_TIMER_FAILED;
|
||||
timer->contextp = strdup(name);
|
||||
|
||||
info = (svc_info_t *)calloc(1, sizeof(svc_info_t));
|
||||
assert(info != NULL);
|
||||
|
||||
info->type = SERVICE_TYPE_TIMER_PUBLIC;
|
||||
info->private = timer;
|
||||
n->private = info;
|
||||
|
||||
dispatch_source_set_event_handler(timer->src, ^{
|
||||
daemon_post((const char *)timer->contextp, 0, 0);
|
||||
});
|
||||
|
||||
dispatch_activate(timer->src);
|
||||
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
service_open_timer_private(const char *name, client_t *c, const char *args)
|
||||
{
|
||||
uint32_t t;
|
||||
time_t s, f, e;
|
||||
int32_t d;
|
||||
name_info_t *n;
|
||||
svc_info_t *info;
|
||||
timer_t *timer;
|
||||
|
||||
call_statistics.service_timer++;
|
||||
|
||||
n = _nc_table_find(&global.notify_state.name_table, name);
|
||||
if (n == NULL) return NOTIFY_STATUS_INVALID_NAME;
|
||||
if (c == NULL) return NOTIFY_STATUS_NULL_INPUT;
|
||||
|
||||
s = f = e = 0;
|
||||
d = 0;
|
||||
|
||||
t = parse_timer_args(args, &s, &f, &e, &d);
|
||||
if (t == TIME_EVENT_NONE) return NOTIFY_STATUS_INVALID_REQUEST;
|
||||
|
||||
if (c->service_index != 0)
|
||||
{
|
||||
/* a client may only have one service */
|
||||
info = (svc_info_t *)service_info_get(c->service_index);
|
||||
if (info->type != SERVICE_TYPE_TIMER_PRIVATE) return NOTIFY_STATUS_INVALID_REQUEST;
|
||||
|
||||
/* the client must be asking for the same timer that is active */
|
||||
timer = (timer_t *)info->private;
|
||||
if ((timer->type != t) || (timer->start != s) || (timer->freq != f) || (timer->end != e) || (timer->day != d)) return NOTIFY_STATUS_INVALID_REQUEST;
|
||||
|
||||
/* the client is already getting notifications for this timer */
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
switch (t)
|
||||
{
|
||||
case TIME_EVENT_ONESHOT:
|
||||
{
|
||||
timer = timer_oneshot(s, global.workloop);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CLOCK:
|
||||
{
|
||||
timer = timer_clock(s, f, e, global.workloop);
|
||||
break;
|
||||
}
|
||||
case TIME_EVENT_CAL:
|
||||
{
|
||||
timer = timer_calendar(s, f, e, d, global.workloop);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return NOTIFY_STATUS_INVALID_TIME_EVENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (timer == NULL) return NOTIFY_STATUS_TIMER_FAILED;
|
||||
timer->context64 = c->cid.hash_key;
|
||||
|
||||
info = (svc_info_t *)calloc(1, sizeof(svc_info_t));
|
||||
assert(info != NULL);
|
||||
|
||||
info->type = SERVICE_TYPE_TIMER_PRIVATE;
|
||||
info->private = timer;
|
||||
c->service_index = service_info_add(info);
|
||||
|
||||
dispatch_source_set_event_handler(timer->src, ^{
|
||||
daemon_post_client(timer->context64);
|
||||
});
|
||||
|
||||
dispatch_activate(timer->src);
|
||||
|
||||
return NOTIFY_STATUS_OK;
|
||||
}
|
||||
|
||||
/* called from server-side routines in notify_proc - services are private to the client */
|
||||
int
|
||||
service_open(const char *name, client_t *client, audit_token_t audit)
|
||||
@ -519,12 +238,6 @@ service_open(const char *name, client_t *client, audit_token_t audit)
|
||||
|
||||
return service_open_path_private(name, client, p, audit, flags);
|
||||
}
|
||||
case SERVICE_TYPE_TIMER_PRIVATE:
|
||||
{
|
||||
p = strchr(name, ':');
|
||||
if (p != NULL) p++;
|
||||
return service_open_timer_private(name, client, p);
|
||||
}
|
||||
default:
|
||||
{
|
||||
return NOTIFY_STATUS_INVALID_REQUEST;
|
||||
@ -549,12 +262,6 @@ service_close(uint16_t service_index)
|
||||
path_node_close((path_node_t *)info->private);
|
||||
break;
|
||||
}
|
||||
case SERVICE_TYPE_TIMER_PUBLIC:
|
||||
case SERVICE_TYPE_TIMER_PRIVATE:
|
||||
{
|
||||
timer_close((timer_t *)info->private);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
}
|
||||
|
@ -27,8 +27,6 @@
|
||||
#define SERVICE_TYPE_NONE 0
|
||||
#define SERVICE_TYPE_PATH_PUBLIC 1
|
||||
#define SERVICE_TYPE_PATH_PRIVATE 2
|
||||
#define SERVICE_TYPE_TIMER_PUBLIC 3
|
||||
#define SERVICE_TYPE_TIMER_PRIVATE 4
|
||||
|
||||
#define SERVICE_PREFIX "com.apple.system.notify.service."
|
||||
#define SERVICE_PREFIX_LEN 32
|
||||
@ -42,8 +40,6 @@ typedef struct
|
||||
int service_open(const char *name, client_t *client, audit_token_t audit);
|
||||
int service_open_path(const char *name, const char *path, uid_t uid, gid_t gid);
|
||||
int service_open_path_private(const char *name, client_t *client, const char *path, audit_token_t audit, uint32_t flags);
|
||||
int service_open_timer(const char *name, const char *args);
|
||||
int service_open_timer_private(const char *name, client_t *client, const char *args);
|
||||
void service_close(uint16_t service_index);
|
||||
void *service_info_get(uint16_t index);
|
||||
|
||||
|
409
notifyd/timer.c
409
notifyd/timer.c
@ -1,409 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <Block.h>
|
||||
#include "timer.h"
|
||||
|
||||
#define MINUTE 60
|
||||
#define HOUR 3600
|
||||
#define DAY 86400
|
||||
|
||||
static const uint8_t mlen[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
/*
|
||||
* Timed events
|
||||
*
|
||||
* Supported event types:
|
||||
*
|
||||
* Oneshot
|
||||
* Every n seconds/minutes/hours/days/weeks
|
||||
* Specific day of the month, every n months
|
||||
* Specific weekday following specific day of the month, every n months
|
||||
*
|
||||
*/
|
||||
static time_t
|
||||
timer_next(timer_t *t, time_t now)
|
||||
{
|
||||
uint32_t y, m;
|
||||
int32_t d, x, a, b, dd, wd;
|
||||
struct tm tmp;
|
||||
time_t next, tt, tod;
|
||||
|
||||
if (t == NULL) return 0;
|
||||
|
||||
switch (t->type)
|
||||
{
|
||||
case TIME_EVENT_ONESHOT:
|
||||
{
|
||||
/*
|
||||
* oneshot time event
|
||||
*/
|
||||
if (t->start < now) return 0;
|
||||
return t->start;
|
||||
}
|
||||
case TIME_EVENT_CLOCK:
|
||||
{
|
||||
/*
|
||||
* event recurs every t->freq seconds
|
||||
*/
|
||||
|
||||
/* t->end is the cut-off. If it's in the past, return 0 */
|
||||
if ((t->end != 0) && (t->end < now)) return 0;
|
||||
|
||||
/* If the start time is in the future, that's the next occurrence */
|
||||
if (t->start >= now) return t->start;
|
||||
|
||||
/* shouldn't happen, as TIME_EVENT_CLOCK should always recur */
|
||||
if (t->freq == 0) return 0;
|
||||
|
||||
x = (int32_t)(((t->freq - 1) + now - t->start) / t->freq);
|
||||
next = t->start + (x * t->freq);
|
||||
return next;
|
||||
}
|
||||
case TIME_EVENT_CAL:
|
||||
{
|
||||
/*
|
||||
* event recurs every t->freq months
|
||||
* t->base gives us the starting month and year, and the time of day
|
||||
* t->day specifies the day of the month (negative means relative to last day of the month)
|
||||
* t->day is > 100 or < 100, then it means a weekday
|
||||
* 101 = first monday, 102 = first tuesday, ..., 108 = second monday, and so on
|
||||
* -101 = last monday, -102 = last tuesday, ..., -108 = second last monday, and so on
|
||||
*/
|
||||
|
||||
/* t->end is the cut-off. If it's in the past, return 0 */
|
||||
if ((t->end != 0) && (t->end < now)) return 0;
|
||||
|
||||
/* If the start time is in the future, that's the next occurrence */
|
||||
if (t->start >= now) return t->start;
|
||||
|
||||
next = t->start;
|
||||
|
||||
/* If t->next is set from the last time we ran, and it is in the past, we can start there. */
|
||||
if ((t->next > 0) && (t->next < now)) next = t->next;
|
||||
|
||||
while (next < now)
|
||||
{
|
||||
/* determine year, month, and time-of-day (clock time) of the next occurance */
|
||||
memset(&tmp, 0, sizeof(struct tm));
|
||||
localtime_r((const time_t *)&(next), &tmp);
|
||||
y = tmp.tm_year;
|
||||
m = tmp.tm_mon;
|
||||
tod = tmp.tm_sec + (MINUTE * tmp.tm_min) + (HOUR * tmp.tm_hour);
|
||||
|
||||
m += t->freq;
|
||||
if (m > 11)
|
||||
{
|
||||
y += (m / 12);
|
||||
m %= 12;
|
||||
}
|
||||
|
||||
/* we now have a year (y), a month (m), and a time of day (tod) */
|
||||
|
||||
if (t->day > 0)
|
||||
{
|
||||
if (t->day < 100)
|
||||
{
|
||||
/* easy case: day is the date of the month */
|
||||
|
||||
memset(&tmp, 0, sizeof(struct tm));
|
||||
tmp.tm_year = y;
|
||||
tmp.tm_mon = m;
|
||||
tmp.tm_mday = t->day;
|
||||
tmp.tm_isdst = -1;
|
||||
next = mktime(&tmp) + tod;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* t->day is a weekday */
|
||||
|
||||
wd = t->day - 100;
|
||||
|
||||
/* start by finding out the weekday of the first of the month */
|
||||
memset(&tmp, 0, sizeof(struct tm));
|
||||
tmp.tm_year = y;
|
||||
tmp.tm_mon = m;
|
||||
tmp.tm_mday = 1;
|
||||
tmp.tm_isdst = -1;
|
||||
tt = mktime(&tmp);
|
||||
localtime_r((const time_t *)&tt, &tmp);
|
||||
|
||||
if (tmp.tm_wday == 0) tmp.tm_wday = 7;
|
||||
|
||||
x = 0;
|
||||
if (tmp.tm_wday > (wd % 7)) x = (wd + 7) - tmp.tm_wday;
|
||||
else x = wd - tmp.tm_wday;
|
||||
|
||||
tmp.tm_mday += x;
|
||||
tmp.tm_isdst = -1;
|
||||
next = mktime(&tmp) + tod;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (t->day > -100)
|
||||
{
|
||||
/* nth day from the end of the month */
|
||||
if (m == 1)
|
||||
{
|
||||
/* determine weekday of last day of February (== March 0) */
|
||||
memset(&tmp, 0, sizeof(struct tm));
|
||||
tmp.tm_year = y;
|
||||
tmp.tm_mon = 2;
|
||||
tmp.tm_mday = 0;
|
||||
tmp.tm_isdst = -1;
|
||||
tt = mktime(&tmp);
|
||||
memset(&tmp, 0, sizeof(struct tm));
|
||||
localtime_r((const time_t *)&(tt), &tmp);
|
||||
d = tmp.tm_mday + t->day;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = mlen[m] + t->day;
|
||||
}
|
||||
|
||||
memset(&tmp, 0, sizeof(struct tm));
|
||||
tmp.tm_year = y;
|
||||
tmp.tm_mon = m;
|
||||
tmp.tm_mday = d;
|
||||
tmp.tm_isdst = -1;
|
||||
next = mktime(&tmp) + tod;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* t->day is a weekday relative to the end of the month */
|
||||
if (m == 1)
|
||||
{
|
||||
/* determine weekday of last day of February (== March 0) */
|
||||
memset(&tmp, 0, sizeof(struct tm));
|
||||
tmp.tm_year = y;
|
||||
tmp.tm_mon = 2;
|
||||
tmp.tm_mday = 0;
|
||||
tmp.tm_isdst = -1;
|
||||
tt = mktime(&tmp);
|
||||
memset(&tmp, 0, sizeof(struct tm));
|
||||
localtime_r((const time_t *)&(tt), &tmp);
|
||||
d = tmp.tm_mday;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = mlen[m];
|
||||
}
|
||||
|
||||
memset(&tmp, 0, sizeof(struct tm));
|
||||
tmp.tm_year = y;
|
||||
tmp.tm_mon = m;
|
||||
tmp.tm_mday = d;
|
||||
tmp.tm_isdst = -1;
|
||||
|
||||
dd = -1 * (t->day + 100);
|
||||
a = dd % 7;
|
||||
b = (dd + 6) / 7;
|
||||
if (a <= tmp.tm_wday) b--;
|
||||
tmp.tm_mday = ((a - tmp.tm_wday) + d) - (b * 7);
|
||||
next = mktime(&tmp) + tod;
|
||||
}
|
||||
|
||||
t->next = next;
|
||||
return next;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* This does the actual free.
|
||||
* It is dispatched on the timer's dispatch source queue to make it safe.
|
||||
*/
|
||||
static void
|
||||
timer_free(timer_t *t)
|
||||
{
|
||||
if (t == NULL) return;
|
||||
if (t->contextp != NULL) free(t->contextp);
|
||||
|
||||
dispatch_release(t->t_src);
|
||||
dispatch_release(t->t_queue);
|
||||
|
||||
memset(t, 0, sizeof(timer_t));
|
||||
free(t);
|
||||
}
|
||||
|
||||
void
|
||||
timer_close(timer_t *t)
|
||||
{
|
||||
if (t == NULL) return;
|
||||
|
||||
if (t->t_src != NULL) dispatch_source_cancel(t->t_src);
|
||||
|
||||
/*
|
||||
* We need to make sure that the source's event handler isn't currently running
|
||||
* before we free the timer. We let the source's queue do the actual free.
|
||||
*/
|
||||
dispatch_async(t->t_queue, ^{ timer_free(t); });
|
||||
}
|
||||
|
||||
timer_t *
|
||||
timer_oneshot(time_t when, dispatch_queue_t queue)
|
||||
{
|
||||
timer_t *t;
|
||||
time_t now;
|
||||
dispatch_time_t trigger;
|
||||
|
||||
/* refuse a trigger time in the past */
|
||||
now = time(0);
|
||||
if (when <= now) return NULL;
|
||||
|
||||
t = calloc(1, sizeof(timer_t));
|
||||
if (t == NULL) return NULL;
|
||||
|
||||
dispatch_retain(queue);
|
||||
|
||||
t->type = TIME_EVENT_ONESHOT;
|
||||
t->start = when;
|
||||
t->t_queue = queue;
|
||||
|
||||
t->t_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
|
||||
t->src = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);
|
||||
|
||||
trigger = dispatch_walltime(NULL, (t->start - now) * NSEC_PER_SEC);
|
||||
dispatch_source_set_timer(t->t_src, trigger, NSEC_PER_SEC, 0);
|
||||
|
||||
dispatch_source_set_event_handler(t->t_src, ^{
|
||||
dispatch_source_merge_data(t->src, 1);
|
||||
dispatch_source_cancel(t->t_src);
|
||||
});
|
||||
|
||||
dispatch_activate(t->t_src);
|
||||
return t;
|
||||
}
|
||||
|
||||
timer_t *
|
||||
timer_clock(time_t first, time_t freq_sec, time_t end, dispatch_queue_t queue)
|
||||
{
|
||||
timer_t *t;
|
||||
time_t now;
|
||||
dispatch_time_t trigger;
|
||||
int64_t x;
|
||||
|
||||
if (freq_sec == 0) return timer_oneshot(first, queue);
|
||||
|
||||
now = time(0);
|
||||
|
||||
t = calloc(1, sizeof(timer_t));
|
||||
if (t == NULL) return NULL;
|
||||
|
||||
t->type = TIME_EVENT_CLOCK;
|
||||
|
||||
if (first < now)
|
||||
{
|
||||
x = ((freq_sec - 1) + now - first) / freq_sec;
|
||||
t->start = first + (x * freq_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
t->start = first;
|
||||
}
|
||||
|
||||
t->end = end;
|
||||
t->freq = (uint32_t)freq_sec;
|
||||
t->t_queue = queue;
|
||||
|
||||
t->t_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
|
||||
t->src = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);
|
||||
|
||||
trigger = dispatch_walltime(NULL, (t->start - now) * NSEC_PER_SEC);
|
||||
dispatch_source_set_timer(t->t_src, trigger, freq_sec * NSEC_PER_SEC, 0);
|
||||
|
||||
dispatch_source_set_event_handler(t->t_src, ^{
|
||||
unsigned long n = dispatch_source_get_data(t->t_src);
|
||||
dispatch_source_merge_data(t->src, n);
|
||||
|
||||
/* deactivate if this is the last time we want to trigger the client source */
|
||||
if ((t->end > 0) && (t->end < (time(0) + freq_sec)))
|
||||
{
|
||||
dispatch_source_cancel(t->t_src);
|
||||
}
|
||||
});
|
||||
|
||||
dispatch_activate(t->t_src);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
timer_t *
|
||||
timer_calendar(time_t first, time_t freq_mth, time_t end, int day, dispatch_queue_t queue)
|
||||
{
|
||||
timer_t *t;
|
||||
time_t next, now;
|
||||
dispatch_time_t trigger;
|
||||
|
||||
if (freq_mth == 0) return timer_oneshot(first, queue);
|
||||
|
||||
now = time(0);
|
||||
|
||||
t = calloc(1, sizeof(timer_t));
|
||||
if (t == NULL) return NULL;
|
||||
|
||||
t->type = TIME_EVENT_CAL;
|
||||
t->start = first;
|
||||
t->day = day;
|
||||
t->end = end;
|
||||
t->freq = (uint32_t)freq_mth;
|
||||
t->t_queue = queue;
|
||||
|
||||
t->t_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
|
||||
t->src = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);
|
||||
|
||||
next = timer_next(t, now);
|
||||
trigger = dispatch_walltime(NULL, (next - now) * NSEC_PER_SEC);
|
||||
dispatch_source_set_timer(t->t_src, trigger, NSEC_PER_SEC, 0);
|
||||
|
||||
dispatch_source_set_event_handler(t->t_src, ^{
|
||||
unsigned long n = dispatch_source_get_data(t->t_src);
|
||||
dispatch_source_merge_data(t->src, n);
|
||||
|
||||
time_t now = time(0);
|
||||
time_t x = timer_next(t, now);
|
||||
|
||||
/* deactivate when there is no next time */
|
||||
if (x == 0)
|
||||
{
|
||||
dispatch_source_cancel(t->t_src);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_source_set_timer(t->t_src, dispatch_walltime(NULL, (x - now) * NSEC_PER_SEC), NSEC_PER_SEC, 0);
|
||||
}
|
||||
});
|
||||
|
||||
dispatch_activate(t->t_src);
|
||||
|
||||
return t;
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
#define TIME_EVENT_NONE 0
|
||||
#define TIME_EVENT_ONESHOT 1
|
||||
#define TIME_EVENT_CLOCK 2
|
||||
#define TIME_EVENT_CAL 3
|
||||
|
||||
/*
|
||||
* Timer Event
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
dispatch_source_t src;
|
||||
dispatch_source_t t_src;
|
||||
dispatch_queue_t t_queue;
|
||||
void *contextp;
|
||||
int64_t start;
|
||||
int64_t end;
|
||||
int64_t next;
|
||||
uint64_t context64;
|
||||
uint32_t freq;
|
||||
uint32_t type;
|
||||
int32_t day;
|
||||
uint32_t context32;
|
||||
} timer_t;
|
||||
|
||||
timer_t *timer_oneshot(time_t when, dispatch_queue_t queue);
|
||||
timer_t *timer_clock(time_t first, time_t freq_sec, time_t end, dispatch_queue_t queue);
|
||||
timer_t *timer_calendar(time_t first, time_t freq_mth, time_t end, int day, dispatch_queue_t queue);
|
||||
|
||||
void timer_close(timer_t *t);
|
0
notifyd/xcodescripts/mk_notify_conf.sh
Normal file → Executable file
0
notifyd/xcodescripts/mk_notify_conf.sh
Normal file → Executable file
@ -209,7 +209,8 @@ process_event(int tid)
|
||||
{
|
||||
struct timeval now;
|
||||
char tstr[32];
|
||||
int status, index, needspace;
|
||||
int status, needspace;
|
||||
uint32_t index;
|
||||
uint64_t state;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
@ -255,7 +256,6 @@ process_event(int tid)
|
||||
{
|
||||
if (needspace) printf(" ");
|
||||
printf("%s", typename[reg[index].type]);
|
||||
needspace = 1;
|
||||
}
|
||||
|
||||
if (printopt != PRINT_QUIET) printf("\n");
|
||||
@ -263,7 +263,7 @@ process_event(int tid)
|
||||
if ((reg[index].count != IndexNull) && (reg[index].count != 0)) reg[index].count--;
|
||||
if (reg[index].count == 0)
|
||||
{
|
||||
status = notify_cancel(tid);
|
||||
(void)notify_cancel(tid);
|
||||
reg_delete(index);
|
||||
}
|
||||
fflush(stdout);
|
||||
@ -406,7 +406,7 @@ do_register(const char *name, uint32_t type, uint32_t signum, uint32_t count)
|
||||
status = notify_register_signal(name, signum, &tid);
|
||||
if (status != NOTIFY_STATUS_OK) return status;
|
||||
|
||||
status = notify_check(tid, &check);
|
||||
(void)notify_check(tid, &check);
|
||||
|
||||
if (sig_src[signum] == NULL)
|
||||
{
|
||||
@ -432,7 +432,7 @@ do_register(const char *name, uint32_t type, uint32_t signum, uint32_t count)
|
||||
status = notify_register_check(name, &tid);
|
||||
if (status != NOTIFY_STATUS_OK) return status;
|
||||
|
||||
status = notify_check(tid, &check);
|
||||
(void)notify_check(tid, &check);
|
||||
|
||||
if (timer_src == NULL)
|
||||
{
|
||||
@ -452,7 +452,7 @@ do_register(const char *name, uint32_t type, uint32_t signum, uint32_t count)
|
||||
status = notify_register_plain(name, &tid);
|
||||
if (status != NOTIFY_STATUS_OK) return status;
|
||||
|
||||
status = notify_check(tid, &check);
|
||||
(void)notify_check(tid, &check);
|
||||
|
||||
if (timer_src == NULL)
|
||||
{
|
||||
@ -478,7 +478,8 @@ int
|
||||
main(int argc, const char *argv[])
|
||||
{
|
||||
const char *name;
|
||||
uint32_t i, n, signum, ntype, status, opts, nap;
|
||||
int i;
|
||||
uint32_t n, signum, ntype, status, opts, nap;
|
||||
int tid;
|
||||
uint64_t state;
|
||||
|
||||
@ -639,7 +640,7 @@ main(int argc, const char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (opts != 0) notify_set_options(opts);
|
||||
if (opts != 0) notify_set_options(opts);
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
|
9
table.h
9
table.h
@ -26,6 +26,7 @@
|
||||
|
||||
#include <os/base.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define _nc_table(key_t, _ns) \
|
||||
struct _nc_table##_ns { \
|
||||
@ -59,9 +60,11 @@ extern void _nc_table_delete(table_t *t, const char *key);
|
||||
extern void _nc_table_delete_n(table_n_t *t, uint32_t key);
|
||||
extern void _nc_table_delete_64(table_64_t *t, uint64_t key);
|
||||
|
||||
extern void _nc_table_foreach(table_t *t, OS_NOESCAPE bool (^)(void *));
|
||||
extern void _nc_table_foreach_n(table_n_t *t, OS_NOESCAPE bool (^)(void *));
|
||||
extern void _nc_table_foreach_64(table_64_t *t, OS_NOESCAPE bool (^)(void *));
|
||||
typedef bool (^payload_handler_t) (void *);
|
||||
|
||||
extern void _nc_table_foreach(table_t *t, OS_NOESCAPE payload_handler_t handler);
|
||||
extern void _nc_table_foreach_n(table_n_t *t, OS_NOESCAPE payload_handler_t handler);
|
||||
extern void _nc_table_foreach_64(table_64_t *t,OS_NOESCAPE payload_handler_t handler);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
@ -51,7 +51,7 @@ ns(_rehash)(struct ns() *t, int direction)
|
||||
|
||||
if (direction > 0) {
|
||||
t->size += (1 << t->grow_shift);
|
||||
if (t->size == (8 << t->grow_shift)) {
|
||||
if (t->size == ((uint32_t)8 << t->grow_shift)) {
|
||||
t->grow_shift++;
|
||||
}
|
||||
} else if (direction < 0) {
|
||||
|
28
tests/Makefile
Normal file
28
tests/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
.PHONY: all installhdrs install $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.targets $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.common Makefile
|
||||
|
||||
PROJECT := Libnotify
|
||||
TEST_DIR := tests/
|
||||
|
||||
DEVELOPER_DIR ?= /Applications/Xcode.app/Contents/Developer/
|
||||
|
||||
ifneq ($(wildcard $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.common),)
|
||||
|
||||
include $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.common
|
||||
|
||||
EXCLUDED_SOURCES := \
|
||||
random_test.c \
|
||||
notify_control.c \
|
||||
notify_test_helper.c \
|
||||
|
||||
OTHER_LDFLAGS := -ldarwintest
|
||||
|
||||
include $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.targets
|
||||
|
||||
|
||||
# fall back if we can't find the Makefile to avoid an error in that case
|
||||
else
|
||||
all:
|
||||
installhdrs:
|
||||
install:
|
||||
mkdir -p $(DSTROOT)/AppleInternal/CoreOS/tests/$(PROJECT)
|
||||
endif
|
63
tests/dispatch_cancel_in_block.c
Normal file
63
tests/dispatch_cancel_in_block.c
Normal file
@ -0,0 +1,63 @@
|
||||
#include <stdlib.h>
|
||||
#include <notify.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <darwintest.h>
|
||||
|
||||
#define KEY "com.apple.notify.test.dispatch_cancel_in_block"
|
||||
#define COUNT 10
|
||||
|
||||
T_DECL(dispatch_cancel_in_block,
|
||||
"Tests notify_cancel in dispatch block.",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
int i;
|
||||
int status;
|
||||
int tokens[COUNT];
|
||||
|
||||
T_LOG("Creating Notify queue");
|
||||
dispatch_queue_t queue = dispatch_queue_create("Notify", NULL);
|
||||
|
||||
T_LOG("Creating dispatch group");
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
|
||||
for (i = 0; i < COUNT; ++i)
|
||||
{
|
||||
dispatch_group_enter(group);
|
||||
|
||||
T_LOG("Registering dispatch notification listeners");
|
||||
status = notify_register_dispatch(KEY, &tokens[i], queue, ^(int x){
|
||||
int is_valid;
|
||||
int status;
|
||||
|
||||
T_LOG("Received dispatch notification: %d", x);
|
||||
|
||||
status = notify_cancel(x);
|
||||
T_EXPECT_EQ(status, NOTIFY_STATUS_OK,
|
||||
"notify_cancel %d == NOTIFY_STATUS_OK", status);
|
||||
|
||||
is_valid = notify_is_valid_token(x);
|
||||
T_EXPECT_EQ(is_valid, 0,
|
||||
"notify_is_valid_token(%d) == %d", x, is_valid);
|
||||
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
|
||||
T_EXPECT_EQ(status, NOTIFY_STATUS_OK,
|
||||
"notify_register_dispatch %d == NOTIFY_STATUS_OK", status);
|
||||
T_EXPECT_TRUE(tokens[i] >= 0, "token %d >= 0", status);
|
||||
}
|
||||
|
||||
T_LOG("Posting notifications");
|
||||
notify_post(KEY);
|
||||
|
||||
dispatch_group_notify(group, queue, ^(void) {
|
||||
printf("Notified...\n");
|
||||
T_END;
|
||||
});
|
||||
|
||||
dispatch_release(queue);
|
||||
dispatch_main();
|
||||
}
|
19
tests/launchd_plists/com.apple.notifyd.test.matching.plist
Normal file
19
tests/launchd_plists/com.apple.notifyd.test.matching.plist
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>LaunchEvents</key>
|
||||
<dict>
|
||||
<key>com.apple.notifyd.matching</key>
|
||||
<dict>
|
||||
<key>foo</key>
|
||||
<dict>
|
||||
<key>Notification</key>
|
||||
<string>com.apple.notifyd.test.matching</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
360
tests/notify_benchmark.c
Normal file
360
tests/notify_benchmark.c
Normal file
@ -0,0 +1,360 @@
|
||||
//
|
||||
// notify_benchmark.c
|
||||
// darwintests
|
||||
//
|
||||
// Created by Brycen Wershing on 7/26/18.
|
||||
//
|
||||
|
||||
#include <darwintest.h>
|
||||
#include <notify.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include "notify_private.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
static const uint32_t CNT = 10;
|
||||
|
||||
#if TARGET_OS_WATCH
|
||||
static const uint32_t SPL = 1000;
|
||||
#else
|
||||
static const uint32_t SPL = 10000;
|
||||
#endif
|
||||
|
||||
static const uint32_t CHECK_WEIGHT = 100;
|
||||
static const uint32_t COAL_WEIGHT = 25;
|
||||
|
||||
// We use bench assert here as it has a lower observer effect than T_* checks.
|
||||
#define bench_assert(X) if(!(X)) {T_FAIL("bench_assertion failed on line %d: %s", __LINE__, #X);}
|
||||
|
||||
static void
|
||||
notify_fence(void)
|
||||
{
|
||||
int fence_token;
|
||||
notify_register_check("com.apple.notify.test", &fence_token);
|
||||
notify_cancel(fence_token);
|
||||
}
|
||||
|
||||
T_DECL(notify_benchmark_post,
|
||||
"notify benchmark post",
|
||||
T_META_EASYPERF(true),
|
||||
T_META_EASYPERF_ARGS("-p notifyd"),
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
uint32_t r;
|
||||
uint32_t i, j;
|
||||
|
||||
int t[CNT];
|
||||
char *n[CNT];
|
||||
size_t l[CNT];
|
||||
|
||||
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = asprintf(&n[i], "dummy.test.%d", i);
|
||||
assert(r != -1);
|
||||
l[i] = strlen(n[i]);
|
||||
}
|
||||
|
||||
for (j = 0 ; j < SPL; j++)
|
||||
{
|
||||
|
||||
|
||||
/* Register Plain */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_register_plain(n[i], &t[i]);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
/* Post 1 */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_post(n[i]);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
/* Post 2 */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_post(n[i]);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
/* Post 3 */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_post(n[i]);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
/* Cancel Plain */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_cancel(t[i]);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
free(n[i]);
|
||||
}
|
||||
|
||||
T_PASS("Notify Benchmark Succeeded!");
|
||||
}
|
||||
|
||||
|
||||
T_DECL(notify_benchmark_state,
|
||||
"notify benchmark state",
|
||||
T_META_EASYPERF(true),
|
||||
T_META_EASYPERF_ARGS("-p notifyd"),
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
uint32_t r;
|
||||
unsigned i, j, k;
|
||||
|
||||
int t[CNT];
|
||||
mach_port_t p[CNT];
|
||||
char *n[CNT];
|
||||
size_t l[CNT];
|
||||
uint64_t s;
|
||||
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = asprintf(&n[i], "dummy.test.%d", i);
|
||||
assert(r != -1);
|
||||
l[i] = strlen(n[i]);
|
||||
}
|
||||
|
||||
for (j = 0 ; j < SPL; j++)
|
||||
{
|
||||
|
||||
|
||||
/* Register Mach Port */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_register_mach_port(n[i], &p[i], 0, &t[i]);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
|
||||
/* Set State 1 */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_set_state(t[i], 1);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
/* Get State */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
uint64_t dummy;
|
||||
r = notify_get_state(t[i], &dummy);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
/* Set State 2 */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_set_state(t[i], 2);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
/* Cancel Port */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_cancel(t[i]);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
free(n[i]);
|
||||
}
|
||||
|
||||
T_PASS("Notify Benchmark Succeeded!");
|
||||
}
|
||||
|
||||
|
||||
|
||||
T_DECL(notify_benchmark_check,
|
||||
"notify benchmark check",
|
||||
T_META_EASYPERF(true),
|
||||
T_META_EASYPERF_ARGS("-p notifyd"),
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
uint32_t r;
|
||||
unsigned i, j, k;
|
||||
|
||||
int t[CNT];
|
||||
char *n[CNT];
|
||||
size_t l[CNT];
|
||||
int check;
|
||||
|
||||
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = asprintf(&n[i], "dummy.test.%d", i);
|
||||
assert(r != -1);
|
||||
l[i] = strlen(n[i]);
|
||||
}
|
||||
|
||||
for (j = 0 ; j < SPL; j++)
|
||||
{
|
||||
|
||||
/* Register Check */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_register_check("com.apple.notify.test.check", &t[i]);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
/* Check 1 */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_check(t[i], &check);
|
||||
bench_assert(r == 0);
|
||||
bench_assert(check == 1);
|
||||
}
|
||||
|
||||
/* Check 2 */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
for(k = 0; k < CHECK_WEIGHT; k++){
|
||||
r = notify_check(t[i], &check);
|
||||
bench_assert(r == 0);
|
||||
bench_assert(check == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check 3 */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
for(k = 0; k < CHECK_WEIGHT; k++){
|
||||
r = notify_check(t[i], &check);
|
||||
bench_assert(r == 0);
|
||||
bench_assert(check == 0);
|
||||
}
|
||||
}
|
||||
|
||||
notify_post("com.apple.notify.test.check");
|
||||
|
||||
notify_fence();
|
||||
|
||||
/* Check 4 */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_check(t[i], &check);
|
||||
bench_assert(r == 0);
|
||||
bench_assert(check == 1);
|
||||
}
|
||||
|
||||
/* Check 5 */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
for(k = 0; k < CHECK_WEIGHT; k++){
|
||||
r = notify_check(t[i], &check);
|
||||
bench_assert(r == 0);
|
||||
bench_assert(check == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cancel Check */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_cancel(t[i]);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
free(n[i]);
|
||||
}
|
||||
|
||||
T_PASS("Notify Benchmark Succeeded!");
|
||||
}
|
||||
|
||||
T_DECL(notify_benchmark_dispatch,
|
||||
"notify benchmark dispatch",
|
||||
T_META_EASYPERF(true),
|
||||
T_META_EASYPERF_ARGS("-p notifyd"),
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
uint32_t r;
|
||||
unsigned i, j, k;
|
||||
|
||||
int t[CNT];
|
||||
int t_2[CNT];
|
||||
char *n[CNT];
|
||||
size_t l[CNT];
|
||||
uint64_t s;
|
||||
__block volatile int dispatch_changer;
|
||||
|
||||
|
||||
dispatch_queue_t disp_q = dispatch_queue_create("Notify.Test", NULL);
|
||||
|
||||
|
||||
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = asprintf(&n[i], "dummy.test.%d", i);
|
||||
assert(r != -1);
|
||||
l[i] = strlen(n[i]);
|
||||
}
|
||||
|
||||
for (j = 0 ; j < SPL; j++)
|
||||
{
|
||||
|
||||
|
||||
/* Register Dispatch 1 */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_register_dispatch(n[i], &t[i], disp_q, ^(int x){
|
||||
dispatch_changer = x;
|
||||
});
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
for (k = 0; k < COAL_WEIGHT; k++){
|
||||
/* Register Dispatch 2 (Coalesced) */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_register_dispatch(n[i], &t_2[i], disp_q, ^(int x){
|
||||
dispatch_changer = x;
|
||||
});
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
|
||||
/* Cancel Coalesced Dispatch */
|
||||
for (i = 0; i < CNT; i++){
|
||||
r = notify_cancel(t_2[i]);
|
||||
bench_assert(r == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cancel Dispatch */
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
r = notify_cancel(t[i]);
|
||||
bench_assert(r == 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < CNT; i++)
|
||||
{
|
||||
free(n[i]);
|
||||
}
|
||||
|
||||
T_PASS("Notify Benchmark Succeeded!");
|
||||
}
|
32
tests/notify_control.c
Normal file
32
tests/notify_control.c
Normal file
@ -0,0 +1,32 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <notify_private.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pid_t pid;
|
||||
int i;
|
||||
uint32_t status;
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "-s"))
|
||||
{
|
||||
pid = atoi(argv[++i]);
|
||||
status = notify_suspend_pid(pid);
|
||||
if (status != 0) printf("suspend pid %d failed status %u\n", pid, status);
|
||||
else printf("suspend pid %d OK\n", pid);
|
||||
}
|
||||
else if (!strcmp(argv[i], "-r"))
|
||||
{
|
||||
pid = atoi(argv[++i]);
|
||||
status = notify_resume_pid(pid);
|
||||
if (status != 0) printf("resume pid %d failed status %u\n", pid, status);
|
||||
else printf("resume pid %d OK\n", pid);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
61
tests/notify_disable_test.c
Normal file
61
tests/notify_disable_test.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <notify.h>
|
||||
#include <notify_private.h>
|
||||
#include <darwintest.h>
|
||||
|
||||
#define KEY1 "com.apple.notify.test.disable"
|
||||
#define KEY2 "com.apple.notify.test.disable.fail"
|
||||
|
||||
T_DECL(notify_disable_test,
|
||||
"notify disable test",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
int token1, token2, status, fd;
|
||||
uint64_t state;
|
||||
|
||||
token1 = NOTIFY_TOKEN_INVALID;
|
||||
token2 = NOTIFY_TOKEN_INVALID;
|
||||
fd = -1;
|
||||
|
||||
status = notify_register_file_descriptor(KEY1, &fd, 0, &token1);
|
||||
T_EXPECT_EQ(status, NOTIFY_STATUS_OK, "notify_register_file_descriptor %d == NOTIFY_STATUS_OK", status);
|
||||
state = 123454321;
|
||||
status = notify_set_state(token1, state);
|
||||
T_EXPECT_EQ(status, NOTIFY_STATUS_OK, "notify_set_state %d == NOTIFY_STATUS_OK", status);
|
||||
|
||||
state = 0;
|
||||
status = notify_get_state(token1, &state);
|
||||
T_EXPECT_EQ(status, NOTIFY_STATUS_OK, "notify_get_state %d == NOTIFY_STATUS_OK", status);
|
||||
T_EXPECT_EQ(state, 123454321ULL, "notify_get_state %llu == 123454321", state);
|
||||
|
||||
// Disable
|
||||
T_LOG("notify_set_options(NOTIFY_OPT_DISABLE)");
|
||||
notify_set_options(NOTIFY_OPT_DISABLE);
|
||||
|
||||
status = notify_register_check(KEY2, &token2);
|
||||
T_EXPECT_NE(status, NOTIFY_STATUS_OK, "notify_register_check %d != NOTIFY_STATUS_OK", status);
|
||||
|
||||
state = 0;
|
||||
status = notify_get_state(token1, &state);
|
||||
T_EXPECT_NE(status, NOTIFY_STATUS_OK, "notify_get_state %d != NOTIFY_STATUS_OK", status);
|
||||
|
||||
// Re-enable
|
||||
T_LOG("notify_set_options(NOTIFY_OPT_ENABLE)");
|
||||
notify_set_options(NOTIFY_OPT_ENABLE);
|
||||
|
||||
state = 0;
|
||||
status = notify_get_state(token1, &state);
|
||||
T_EXPECT_EQ(status, NOTIFY_STATUS_OK, "notify_get_state %d == NOTIFY_STATUS_OK", status);
|
||||
T_EXPECT_EQ(state, 123454321ULL, "notify_get_state %llu == 123454321", state);
|
||||
|
||||
T_LOG("checking token validity");
|
||||
status = notify_is_valid_token(token1);
|
||||
T_EXPECT_GT(status, 0, "notify_is_valid_token(token1) > 0 (%d)", status);
|
||||
|
||||
T_LOG("canceling token1");
|
||||
notify_cancel(token1);
|
||||
status = notify_is_valid_token(token1);
|
||||
T_EXPECT_EQ(status, 0, "notify_is_valid_token(token1) == 0 (%d)", status);
|
||||
}
|
57
tests/notify_exec.c
Normal file
57
tests/notify_exec.c
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// notify_exec.c
|
||||
// darwintests
|
||||
//
|
||||
// Created by Brycen Wershing on 2/10/20.
|
||||
//
|
||||
|
||||
#include <darwintest.h>
|
||||
#include <notify.h>
|
||||
#include <notify_private.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern char **environ;
|
||||
|
||||
T_DECL(notify_exec,
|
||||
"notify exec",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "true"))
|
||||
{
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == 0) {
|
||||
printf("Child started up\n");
|
||||
|
||||
char *argv[3];
|
||||
argv[0] = "notify_test_helper";
|
||||
argv[1] = "Continue";
|
||||
argv[2] = NULL;
|
||||
|
||||
execve("/AppleInternal/Tests/Libnotify/notify_test_helper" ,argv , environ);
|
||||
printf("execve failed with %d\n", errno);
|
||||
abort();
|
||||
} else {
|
||||
int status;
|
||||
T_LOG("Fork returned %d", pid);
|
||||
pid = waitpid(pid, &status, 0);
|
||||
if (pid == -1) {
|
||||
T_FAIL("wait4 failed with %d", errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WIFEXITED(status)) {
|
||||
T_FAIL("Unexpected helper termination");
|
||||
return;
|
||||
}
|
||||
|
||||
int exitStatus = WEXITSTATUS(status);
|
||||
|
||||
if (exitStatus == 42) {
|
||||
T_PASS("Succeeded!");
|
||||
} else {
|
||||
T_FAIL("Failed with %d", exitStatus);
|
||||
}
|
||||
}
|
||||
}
|
6
tests/notify_leaks.c
Normal file
6
tests/notify_leaks.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <darwintest_utils.h>
|
||||
|
||||
T_DECL(notify_leaks, "checks for leaks in notifyd", T_META_ASROOT(true))
|
||||
{
|
||||
dt_check_leaks_by_name("notifyd");
|
||||
}
|
100
tests/notify_many_dups.c
Normal file
100
tests/notify_many_dups.c
Normal file
@ -0,0 +1,100 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <notify.h>
|
||||
#include <darwintest.h>
|
||||
|
||||
T_DECL(notify_many_dups,
|
||||
"notify many duplicate registration test",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"),
|
||||
T_META_IGNORECRASHES("notify_many_dups*"))
|
||||
{
|
||||
int t, n, i;
|
||||
uint32_t status;
|
||||
mach_port_t port = MACH_PORT_NULL;
|
||||
const char *name = "com.apple.notify.many.dups.test";
|
||||
|
||||
n = 50000;
|
||||
|
||||
status = notify_register_mach_port(name, &port, 0, &t);
|
||||
T_EXPECT_EQ_INT(status, NOTIFY_STATUS_OK, "notify_register_mach_port status == NOTIFY_STATUS_OK");
|
||||
for (i = 1; i < n; i++)
|
||||
{
|
||||
status = notify_register_mach_port(name, &port, NOTIFY_REUSE, &t);
|
||||
|
||||
if (status != NOTIFY_STATUS_OK) {
|
||||
T_FAIL("notify_register_mach_port status != NOTIFY_STATUS_OK (status: %d, iteration: %d", status, i);
|
||||
}
|
||||
}
|
||||
T_PASS("Successfully registered %d times for name %s\n", n, name);
|
||||
}
|
||||
|
||||
#define notify_many_dups_number 500
|
||||
|
||||
T_DECL(notify_many_dups_posts,
|
||||
"notify many duplicate registration posting test",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"),
|
||||
T_META_IGNORECRASHES("notify_many_dups*"))
|
||||
{
|
||||
int i;
|
||||
uint32_t status;
|
||||
mach_port_t port = MACH_PORT_NULL;
|
||||
const char *name = "com.apple.notify.many.dups.post.test";
|
||||
|
||||
int tokens[notify_many_dups_number];
|
||||
|
||||
|
||||
status = notify_register_mach_port(name, &port, 0, &tokens[0]);
|
||||
T_EXPECT_EQ_INT(status, NOTIFY_STATUS_OK, "notify_register_mach_port status == NOTIFY_STATUS_OK");
|
||||
for (i = 1; i < notify_many_dups_number; i++)
|
||||
{
|
||||
tokens[i] = NOTIFY_TOKEN_INVALID;
|
||||
status = notify_register_mach_port(name, &port, NOTIFY_REUSE, &tokens[i]);
|
||||
|
||||
if (status != NOTIFY_STATUS_OK) {
|
||||
T_FAIL("notify_register_mach_port status != NOTIFY_STATUS_OK (status: %d, iteration: %d)", status, i);
|
||||
}
|
||||
if (tokens[i] == NOTIFY_TOKEN_INVALID) {
|
||||
T_FAIL("notify_register_mach_port did not set token (iteration: %d)", i);
|
||||
}
|
||||
}
|
||||
T_PASS("Successfully registered %d times for name %s\n", notify_many_dups_number, name);
|
||||
|
||||
notify_post(name);
|
||||
|
||||
sleep(1);
|
||||
|
||||
while (true) {
|
||||
int tid;
|
||||
mach_msg_empty_rcv_t msg;
|
||||
kern_return_t status;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
status = mach_msg(&msg.header, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof(msg), port, 100, MACH_PORT_NULL);
|
||||
if (status != KERN_SUCCESS) {
|
||||
T_LOG("mach msg returned %d", status);
|
||||
break;
|
||||
}
|
||||
|
||||
tid = msg.header.msgh_id;
|
||||
|
||||
for (int j = 0; j < notify_many_dups_number; j++) {
|
||||
if (tokens[j] == tid) {
|
||||
T_PASS("Received message for registration %d (%d)", j, tokens[j]);
|
||||
tokens[j] = 0;
|
||||
notify_cancel(tid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k < notify_many_dups_number; k++) {
|
||||
if (tokens[k] != 0) {
|
||||
notify_cancel(tokens[k]);
|
||||
T_FAIL("Did not receive notification for %d (%d)", k, tokens[k]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
113
tests/notify_matching.c
Normal file
113
tests/notify_matching.c
Normal file
@ -0,0 +1,113 @@
|
||||
#include <darwintest.h>
|
||||
#include <darwintest_multiprocess.h>
|
||||
|
||||
#include <notify.h>
|
||||
#include <xpc/private.h>
|
||||
|
||||
T_DECL(notify_matching, "notifyd.matching plist registration",
|
||||
T_META_LAUNCHD_PLIST("com.apple.notifyd.test.matching.plist"))
|
||||
{
|
||||
xpc_set_event_stream_handler("com.apple.notifyd.matching", dispatch_get_main_queue(),
|
||||
^(xpc_object_t event) {
|
||||
T_ASSERT_EQ_STR(xpc_dictionary_get_string(event, "Notification"), "com.apple.notifyd.test.matching", NULL);
|
||||
T_END;
|
||||
});
|
||||
|
||||
uint32_t status = notify_post("com.apple.notifyd.test.matching");
|
||||
T_ASSERT_EQ(status, NOTIFY_STATUS_OK, NULL);
|
||||
|
||||
dispatch_main();
|
||||
}
|
||||
|
||||
T_DECL(notify_matching_state, "notifyd.matching plist registration with event that carries state",
|
||||
T_META_LAUNCHD_PLIST("com.apple.notifyd.test.matching.plist"))
|
||||
{
|
||||
xpc_set_event_stream_handler("com.apple.notifyd.matching", dispatch_get_main_queue(),
|
||||
^(xpc_object_t event) {
|
||||
T_ASSERT_EQ_STR(xpc_dictionary_get_string(event, "Notification"), "com.apple.notifyd.test.matching", NULL);
|
||||
T_ASSERT_EQ((int)xpc_dictionary_get_uint64(event, "_State"), 42, NULL);
|
||||
T_END;
|
||||
});
|
||||
|
||||
int token;
|
||||
uint32_t status = notify_register_check("com.apple.notifyd.test.matching", &token);
|
||||
T_ASSERT_EQ(status, NOTIFY_STATUS_OK, NULL);
|
||||
|
||||
status = notify_set_state(token, 42);
|
||||
T_ASSERT_EQ(status, NOTIFY_STATUS_OK, NULL);
|
||||
|
||||
status = notify_post("com.apple.notifyd.test.matching");
|
||||
T_ASSERT_EQ(status, NOTIFY_STATUS_OK, NULL);
|
||||
|
||||
dispatch_main();
|
||||
}
|
||||
|
||||
T_HELPER_DECL(notify_matching_system_impl, "implementation for notify_matching_system")
|
||||
{
|
||||
xpc_set_event_stream_handler("com.apple.notifyd.matching", dispatch_get_main_queue(),
|
||||
^(xpc_object_t event) {
|
||||
T_ASSERT_EQ_STR(xpc_dictionary_get_string(event, "Notification"), "com.apple.notifyd.test.matching", NULL);
|
||||
T_END;
|
||||
});
|
||||
|
||||
uint32_t status = notify_post("com.apple.notifyd.test.matching");
|
||||
T_ASSERT_EQ(status, NOTIFY_STATUS_OK, NULL);
|
||||
|
||||
dispatch_main();
|
||||
}
|
||||
|
||||
T_DECL(notify_matching_system, "notifyd.matching plist registration in the system domain",
|
||||
T_META_ASROOT(true))
|
||||
{
|
||||
dt_helper_t helpers[] = {
|
||||
dt_launchd_helper_domain("com.apple.notifyd.test.matching.plist", "notify_matching_system_impl", NULL, LAUNCH_SYSTEM_DOMAIN)
|
||||
};
|
||||
dt_run_helpers(helpers, 1, 60);
|
||||
}
|
||||
|
||||
T_DECL(notify_matching_runtime, "notifyd.matching at runtime",
|
||||
T_META("launchd_plist", "RunAtLoad.plist"))
|
||||
{
|
||||
xpc_set_event_stream_handler("com.apple.notifyd.matching", dispatch_get_main_queue(),
|
||||
^(xpc_object_t event) {
|
||||
T_ASSERT_EQ_STR(xpc_dictionary_get_string(event, "Notification"), "com.apple.notifyd.test.matching_runtime", NULL);
|
||||
T_END;
|
||||
});
|
||||
|
||||
xpc_object_t registration = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_string(registration, "Notification", "com.apple.notifyd.test.matching_runtime");
|
||||
xpc_set_event("com.apple.notifyd.matching", "foo", registration);
|
||||
|
||||
// Gross. xpc_set_event is asynchronous, wait for a few sec before posting
|
||||
dispatch_after(_dispatch_time_after_sec(5), dispatch_get_main_queue(), ^{
|
||||
uint32_t status = notify_post("com.apple.notifyd.test.matching_runtime");
|
||||
T_ASSERT_EQ(status, NOTIFY_STATUS_OK, NULL);
|
||||
});
|
||||
|
||||
dispatch_main();
|
||||
}
|
||||
|
||||
T_DECL(notify_matching_uid, "notifyd.matching uid registration",
|
||||
T_META("launchd_plist", "RunAtLoad.plist"))
|
||||
{
|
||||
char *name = NULL;
|
||||
asprintf(&name, "user.uid.%d.com.apple.notifyd.test.matching_uid", getuid());
|
||||
|
||||
xpc_set_event_stream_handler("com.apple.notifyd.matching", dispatch_get_main_queue(),
|
||||
^(xpc_object_t event) {
|
||||
T_ASSERT_EQ_STR(xpc_dictionary_get_string(event, "Notification"), name, NULL);
|
||||
T_END;
|
||||
});
|
||||
|
||||
xpc_object_t registration = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_string(registration, "Notification", name);
|
||||
xpc_set_event("com.apple.notifyd.matching", "foo", registration);
|
||||
|
||||
// Gross. xpc_set_event is asynchronous, wait for a few sec before posting
|
||||
dispatch_after(_dispatch_time_after_sec(5), dispatch_get_main_queue(), ^{
|
||||
uint32_t status = notify_post(name);
|
||||
T_ASSERT_EQ(status, NOTIFY_STATUS_OK, NULL);
|
||||
});
|
||||
|
||||
dispatch_main();
|
||||
}
|
187
tests/notify_pathwatch.c
Normal file
187
tests/notify_pathwatch.c
Normal file
@ -0,0 +1,187 @@
|
||||
//
|
||||
// notify_pathwatch.c
|
||||
// tests
|
||||
//
|
||||
// Created by Brycen Wershing on 8/2/18.
|
||||
//
|
||||
|
||||
#include <darwintest.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <notify.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <mach/mach.h>
|
||||
#include <darwintest_multiprocess.h>
|
||||
#include "notify_private.h"
|
||||
|
||||
int dispatch_changer;
|
||||
|
||||
#define PATHWATCH_TEST_NAME "com.example.test.pathwatch"
|
||||
#define PATHWATCH_TEST_FILE "/tmp/notify_pathwatch.test"
|
||||
|
||||
T_DECL(notify_pathwatch,
|
||||
"notify pathwatch test",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "true"))
|
||||
{
|
||||
dispatch_queue_t testQueue = dispatch_queue_create("testQ", DISPATCH_QUEUE_SERIAL);
|
||||
uint32_t rc;
|
||||
static int check_token = NOTIFY_TOKEN_INVALID;
|
||||
static int disp_token = NOTIFY_TOKEN_INVALID;
|
||||
int check;
|
||||
uint64_t state;
|
||||
int fd, bytes_written;
|
||||
|
||||
dispatch_changer = 0;
|
||||
|
||||
|
||||
// register for check and dispatch
|
||||
|
||||
rc = notify_register_check(PATHWATCH_TEST_NAME, &check_token);
|
||||
assert(rc == NOTIFY_STATUS_OK);
|
||||
|
||||
rc = notify_check(check_token, &check);
|
||||
assert(rc == NOTIFY_STATUS_OK);
|
||||
assert(check == 1);
|
||||
|
||||
rc = notify_register_dispatch(PATHWATCH_TEST_NAME, &disp_token, testQueue, ^(int i){dispatch_changer++;});
|
||||
assert(rc == NOTIFY_STATUS_OK);
|
||||
|
||||
|
||||
// add file monitoring for nonexistant file
|
||||
unlink(PATHWATCH_TEST_FILE); // return code ignored because the file probably does not exist
|
||||
|
||||
|
||||
notify_monitor_file(check_token, PATHWATCH_TEST_FILE, 0x3ff);
|
||||
notify_monitor_file(disp_token, PATHWATCH_TEST_FILE, 0x3ff);
|
||||
|
||||
|
||||
// there should not be a post yet
|
||||
dispatch_sync(testQueue, ^{assert(
|
||||
dispatch_changer == 0);
|
||||
});
|
||||
|
||||
rc = notify_check(check_token, &check);
|
||||
assert(rc == NOTIFY_STATUS_OK);
|
||||
assert(check == 0);
|
||||
|
||||
|
||||
// post and fence
|
||||
rc = notify_post(PATHWATCH_TEST_NAME);
|
||||
assert(rc == NOTIFY_STATUS_OK);
|
||||
|
||||
notify_get_state(check_token, &state); //fence
|
||||
sleep(1);
|
||||
|
||||
// check to make sure post was good
|
||||
rc = notify_check(check_token, &check);
|
||||
assert(rc == NOTIFY_STATUS_OK);
|
||||
assert(check == 1);
|
||||
|
||||
dispatch_sync(testQueue, ^{
|
||||
assert(dispatch_changer == 1);
|
||||
dispatch_changer = 0;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// create the file
|
||||
fd = creat(PATHWATCH_TEST_FILE, 0);
|
||||
assert(fd != -1);
|
||||
|
||||
sleep(1);
|
||||
notify_get_state(check_token, &state); //fence
|
||||
|
||||
// check to make sure post was good
|
||||
rc = notify_check(check_token, &check);
|
||||
assert(rc == NOTIFY_STATUS_OK);
|
||||
assert(check == 1);
|
||||
|
||||
dispatch_sync(testQueue, ^{
|
||||
assert(dispatch_changer == 1);
|
||||
dispatch_changer = 0;
|
||||
});
|
||||
|
||||
|
||||
// write something to the file
|
||||
bytes_written = write(fd, "this", 4);
|
||||
assert(bytes_written == 4);
|
||||
|
||||
sleep(1);
|
||||
notify_get_state(check_token, &state); //fence
|
||||
|
||||
// check to make sure post was good
|
||||
rc = notify_check(check_token, &check);
|
||||
assert(rc == NOTIFY_STATUS_OK);
|
||||
assert(check == 1);
|
||||
|
||||
dispatch_sync(testQueue, ^{
|
||||
assert(dispatch_changer == 1);
|
||||
dispatch_changer = 0;
|
||||
});
|
||||
|
||||
|
||||
// delete the file
|
||||
rc = close(fd);
|
||||
assert(rc == 0);
|
||||
|
||||
unlink(PATHWATCH_TEST_FILE);
|
||||
|
||||
sleep(1);
|
||||
notify_get_state(check_token, &state); //fence
|
||||
|
||||
// check to make sure post was good
|
||||
rc = notify_check(check_token, &check);
|
||||
assert(rc == NOTIFY_STATUS_OK);
|
||||
assert(check == 1);
|
||||
|
||||
dispatch_sync(testQueue, ^{
|
||||
assert(dispatch_changer == 1);
|
||||
dispatch_changer = 0;
|
||||
});
|
||||
|
||||
// cleanup
|
||||
rc = notify_cancel(check_token);
|
||||
assert(rc == NOTIFY_STATUS_OK);
|
||||
|
||||
rc = notify_cancel(disp_token);
|
||||
assert(rc == NOTIFY_STATUS_OK);
|
||||
|
||||
dispatch_release(testQueue);
|
||||
|
||||
fd = creat(PATHWATCH_TEST_FILE, 0);
|
||||
assert(fd != -1);
|
||||
|
||||
|
||||
dt_helper_t helpers[50];
|
||||
for(int i = 0; i < 50; i++){
|
||||
helpers[i] = dt_child_helper("notify_pathwatch_helper");
|
||||
}
|
||||
|
||||
dt_run_helpers(helpers, 50, 180);
|
||||
|
||||
rc = close(fd);
|
||||
assert(rc == 0);
|
||||
|
||||
unlink(PATHWATCH_TEST_FILE);
|
||||
|
||||
|
||||
T_PASS("Success");
|
||||
}
|
||||
|
||||
|
||||
T_HELPER_DECL(notify_pathwatch_helper,
|
||||
"notify pathwatch test helper",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"))
|
||||
{
|
||||
int token;
|
||||
char *filename;
|
||||
uint32_t block_rc;
|
||||
block_rc = notify_register_check(PATHWATCH_TEST_NAME, &token);
|
||||
assert(block_rc == NOTIFY_STATUS_OK);
|
||||
notify_monitor_file(token, PATHWATCH_TEST_FILE, 0x3ff);
|
||||
T_PASS("Helper passed");
|
||||
T_END;
|
||||
exit(0);
|
||||
}
|
71
tests/notify_qos.c
Normal file
71
tests/notify_qos.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include <stdlib.h>
|
||||
#include <notify.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <darwintest.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define KEY "com.apple.notify.test.notify_register_signal"
|
||||
|
||||
#define HANDLED 1
|
||||
#define UNHANDLED 0
|
||||
|
||||
// Notification token
|
||||
int n_token;
|
||||
|
||||
// Global to show if notification was handled
|
||||
int handled = 0;
|
||||
|
||||
void post_notification(char * msg, int should_handle) {
|
||||
int i, loops = 5000; //5000*10 = 50,000 = 50ms
|
||||
|
||||
// Post notification
|
||||
handled = UNHANDLED;
|
||||
T_LOG("%s", msg);
|
||||
notify_post(KEY);
|
||||
|
||||
for(i=0; i < loops; i++) {
|
||||
if(handled == HANDLED)
|
||||
break;
|
||||
else
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
if(should_handle)
|
||||
T_EXPECT_EQ(handled, (should_handle ? HANDLED : UNHANDLED),
|
||||
"Signal based notification handled as expected.");
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
// Register with notification system
|
||||
dispatch_queue_t dq = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
|
||||
int rv = notify_register_dispatch(KEY, &n_token, dq, ^(int token){
|
||||
handled = HANDLED;
|
||||
|
||||
qos_class_t block_qos = qos_class_self();
|
||||
if (block_qos != QOS_CLASS_DEFAULT){
|
||||
T_FAIL("Block is running at QoS %#x instead of DEF", block_qos);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
if (rv)
|
||||
T_FAIL("Unable to notify_register_dispatch");
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
notify_cancel(n_token); /* Releases the queue - block must finish executing */
|
||||
}
|
||||
|
||||
T_DECL(notify_qos,
|
||||
"Test that work for notification runs at qos of target queue",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
setup();
|
||||
|
||||
post_notification("Ensure notifications are being handled properly.", 1);
|
||||
|
||||
cleanup();
|
||||
}
|
129
tests/notify_regenerate.c
Normal file
129
tests/notify_regenerate.c
Normal file
@ -0,0 +1,129 @@
|
||||
#include <stdlib.h>
|
||||
#include <notify.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <darwintest.h>
|
||||
#include <signal.h>
|
||||
#include "../libnotify.h"
|
||||
|
||||
#define T_ASSERT_GROUP_WAIT(g, timeout, ...) ({ \
|
||||
dispatch_time_t _timeout = dispatch_time(DISPATCH_TIME_NOW, \
|
||||
(uint64_t)(timeout * NSEC_PER_SEC)); \
|
||||
T_ASSERT_FALSE(dispatch_group_wait(g, _timeout), __VA_ARGS__); \
|
||||
})
|
||||
|
||||
static bool has_port_been_notified;
|
||||
static int m_token;
|
||||
|
||||
static void port_handler(mach_port_t port)
|
||||
{
|
||||
int tid;
|
||||
mach_msg_empty_rcv_t msg;
|
||||
kern_return_t status;
|
||||
|
||||
if (port == MACH_PORT_NULL) return;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
status = mach_msg(&msg.header, MACH_RCV_MSG, 0, sizeof(msg), port, 0, MACH_PORT_NULL);
|
||||
if (status != KERN_SUCCESS) return;
|
||||
|
||||
tid = msg.header.msgh_id;
|
||||
|
||||
T_ASSERT_EQ(m_token, tid, "port_handler should be called with mach_port token");
|
||||
|
||||
has_port_been_notified = true;
|
||||
|
||||
}
|
||||
|
||||
T_DECL(notify_regenerate, "Make sure regenerate registrations works",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META_ASROOT(YES))
|
||||
{
|
||||
const char *KEY = "com.apple.notify.test.regenerate";
|
||||
int v_token, n_token, rc;
|
||||
pid_t old_pid, new_pid;
|
||||
uint64_t state;
|
||||
mach_port_t watch_port;
|
||||
dispatch_source_t port_src;
|
||||
|
||||
dispatch_queue_t watch_queue = dispatch_queue_create("Watch Q", NULL);
|
||||
dispatch_queue_t dq = dispatch_queue_create_with_target("q", NULL, NULL);
|
||||
dispatch_group_t dg = dispatch_group_create();
|
||||
|
||||
T_LOG("Grab the current instance pid & version");
|
||||
{
|
||||
rc = notify_register_check(NOTIFY_IPC_VERSION_NAME, &v_token);
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "register_check(NOTIFY_IPC_VERSION_NAME)");
|
||||
|
||||
state = ~0ull;
|
||||
rc = notify_get_state(v_token, &state);
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "notify_get_state(NOTIFY_IPC_VERSION_NAME)");
|
||||
|
||||
old_pid = (pid_t)(state >> 32);
|
||||
T_EXPECT_EQ((uint32_t)state, NOTIFY_IPC_VERSION, "IPC version should be set");
|
||||
}
|
||||
|
||||
T_LOG("Register for our test topic, and check it works");
|
||||
{
|
||||
rc = notify_register_mach_port(KEY, &watch_port, 0, &m_token);
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "register mach port should work");
|
||||
|
||||
port_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, watch_port, 0, watch_queue);
|
||||
dispatch_source_set_event_handler(port_src, ^{
|
||||
port_handler(watch_port);
|
||||
});
|
||||
dispatch_activate(port_src);
|
||||
|
||||
|
||||
rc = notify_register_dispatch(KEY, &n_token, dq, ^(int token){
|
||||
// if we crash here, it means we got a spurious post
|
||||
// e.g. if you run the test twice concurrently this could happen
|
||||
dispatch_group_leave(dg);
|
||||
});
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "register dispatch should work");
|
||||
|
||||
dispatch_group_enter(dg);
|
||||
has_port_been_notified = false;
|
||||
notify_post(KEY);
|
||||
sleep(1);
|
||||
T_ASSERT_GROUP_WAIT(dg, 5., "we received our own notification");
|
||||
T_ASSERT_EQ(has_port_been_notified, true, "mach port should receive notification");
|
||||
}
|
||||
|
||||
T_LOG("Make sure notifyd changes pid due to a kill");
|
||||
{
|
||||
state = ~0ull;
|
||||
rc = notify_get_state(v_token, &state);
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "notify_get_state(NOTIFY_IPC_VERSION_NAME)");
|
||||
|
||||
new_pid = (pid_t)(state >> 32);
|
||||
T_ASSERT_EQ(old_pid, new_pid, "Pid should not have changed yet");
|
||||
|
||||
rc = kill(old_pid, SIGKILL);
|
||||
T_ASSERT_POSIX_SUCCESS(rc, "Killing notifyd");
|
||||
|
||||
new_pid = old_pid;
|
||||
for (int i = 0; i < 10 && new_pid == old_pid; i++) {
|
||||
usleep(100000); /* wait for .1s for notifyd to die */
|
||||
state = ~0ull;
|
||||
rc = notify_get_state(v_token, &state);
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "notify_get_state(NOTIFY_IPC_VERSION_NAME)");
|
||||
new_pid = (pid_t)(state >> 32);
|
||||
}
|
||||
T_ASSERT_NE(old_pid, new_pid, "Pid should have changed within 1s");
|
||||
}
|
||||
|
||||
T_LOG("Make sure our old registration works");
|
||||
{
|
||||
// No-dispatch mach port registrations don't regenerate
|
||||
|
||||
dispatch_group_enter(dg);
|
||||
notify_post(KEY);
|
||||
sleep(1);
|
||||
T_ASSERT_GROUP_WAIT(dg, 5., "we received our own notification");
|
||||
}
|
||||
|
||||
dispatch_release(port_src);
|
||||
|
||||
}
|
32
tests/notify_register_file_desc.c
Normal file
32
tests/notify_register_file_desc.c
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// notify_register_file_desc.c
|
||||
//
|
||||
// Created by Brycen Wershing on 6/29/20.
|
||||
//
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <notify.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <darwintest.h>
|
||||
#include <signal.h>
|
||||
#include "../libnotify.h"
|
||||
|
||||
T_DECL(notify_register_file_desc, "Make sure mach port registrations works",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META_ASROOT(YES))
|
||||
{
|
||||
const char *KEY = "com.apple.notify.test.file_desc";
|
||||
int rc, fd, tok;
|
||||
|
||||
rc = notify_register_file_descriptor(KEY, &fd, 0, &tok);
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "register file desc should work");
|
||||
T_ASSERT_NE(fcntl(fd, F_GETFD), -1, "file descriptor should exist");
|
||||
|
||||
rc = notify_cancel(tok);
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "cancel should work");
|
||||
T_ASSERT_EQ(fcntl(fd, F_GETFD), -1, "file descriptor should not exist");
|
||||
}
|
||||
|
94
tests/notify_register_mach_port.c
Normal file
94
tests/notify_register_mach_port.c
Normal file
@ -0,0 +1,94 @@
|
||||
//
|
||||
// notify_register_mach_port.c
|
||||
// Libnotify
|
||||
//
|
||||
// Created by Brycen Wershing on 10/23/19.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <notify.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <darwintest.h>
|
||||
#include <signal.h>
|
||||
#include "../libnotify.h"
|
||||
|
||||
static bool has_port_been_notified_1, has_port_been_notified_2;
|
||||
static int key_1_token, key_2_token;
|
||||
|
||||
static void port_handler(mach_port_t port)
|
||||
{
|
||||
int tid;
|
||||
mach_msg_empty_rcv_t msg;
|
||||
kern_return_t status;
|
||||
|
||||
if (port == MACH_PORT_NULL) return;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
status = mach_msg(&msg.header, MACH_RCV_MSG, 0, sizeof(msg), port, 0, MACH_PORT_NULL);
|
||||
if (status != KERN_SUCCESS) return;
|
||||
|
||||
tid = msg.header.msgh_id;
|
||||
if (tid == key_1_token)
|
||||
{
|
||||
has_port_been_notified_1 = true;
|
||||
}
|
||||
else if (tid == key_2_token)
|
||||
{
|
||||
has_port_been_notified_2 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
T_FAIL("port handler should only be called with tokens %d and %d, but it was called with %d",
|
||||
key_1_token, key_2_token, tid);
|
||||
}
|
||||
}
|
||||
|
||||
T_DECL(notify_register_mach_port, "Make sure mach port registrations works",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META_ASROOT(YES))
|
||||
{
|
||||
const char *KEY1 = "com.apple.notify.test.mach_port.1";
|
||||
const char *KEY2 = "com.apple.notify.test.mach_port.2";
|
||||
int rc;
|
||||
|
||||
// Make sure that posts without an existing registration don't do anything
|
||||
// bad, like crash notifyd or break future posts
|
||||
notify_post(KEY1);
|
||||
notify_post(KEY1);
|
||||
notify_post(KEY1);
|
||||
|
||||
mach_port_t watch_port;
|
||||
dispatch_source_t port_src;
|
||||
dispatch_queue_t watch_queue = dispatch_queue_create("Watch Q", NULL);
|
||||
|
||||
rc = notify_register_mach_port(KEY1, &watch_port, 0, &key_1_token);
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "register mach port should work");
|
||||
|
||||
rc = notify_register_mach_port(KEY2, &watch_port, NOTIFY_REUSE, &key_2_token);
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "register mach port should work");
|
||||
|
||||
port_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, watch_port, 0, watch_queue);
|
||||
dispatch_source_set_event_handler(port_src, ^{
|
||||
port_handler(watch_port);
|
||||
});
|
||||
dispatch_activate(port_src);
|
||||
|
||||
has_port_been_notified_1 = false;
|
||||
has_port_been_notified_2 = false;
|
||||
notify_post(KEY1);
|
||||
sleep(1);
|
||||
T_ASSERT_EQ(has_port_been_notified_1, true, "mach port 1 should receive notification");
|
||||
T_ASSERT_EQ(has_port_been_notified_2, false, "mach port 2 should not receive notification");
|
||||
|
||||
has_port_been_notified_1 = false;
|
||||
has_port_been_notified_2 = false;
|
||||
notify_post(KEY2);
|
||||
sleep(1);
|
||||
T_ASSERT_EQ(has_port_been_notified_1, false, "mach port 1 should not receive notification");
|
||||
T_ASSERT_EQ(has_port_been_notified_2, true, "mach port 2 should receive notification");
|
||||
|
||||
dispatch_release(port_src);
|
||||
|
||||
}
|
163
tests/notify_register_signal.c
Normal file
163
tests/notify_register_signal.c
Normal file
@ -0,0 +1,163 @@
|
||||
#include <stdlib.h>
|
||||
#include <notify.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <darwintest.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define KEY "com.apple.notify.test.notify_register_signal"
|
||||
|
||||
void poster(char * msg);
|
||||
|
||||
#define HANDLED 1
|
||||
#define UNHANDLED 0
|
||||
|
||||
// Notification token
|
||||
int n_token;
|
||||
|
||||
// Global to show if notification was handled
|
||||
int handled = 0;
|
||||
|
||||
void post_notification(char * msg, int should_handle) {
|
||||
int i, loops = 100;
|
||||
|
||||
// Post notification
|
||||
handled = 0;
|
||||
T_LOG("%s", msg);
|
||||
notify_post(KEY);
|
||||
|
||||
for(i=0; i < loops; i++) {
|
||||
if(handled == HANDLED)
|
||||
break;
|
||||
else
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
if(should_handle)
|
||||
T_EXPECT_EQ(handled, (should_handle ? HANDLED : UNHANDLED),
|
||||
"Signal based notification handled as expected.");
|
||||
}
|
||||
|
||||
int check() {
|
||||
int status;
|
||||
uint32_t rv;
|
||||
|
||||
rv = notify_check(n_token, &status);
|
||||
|
||||
if(rv != NOTIFY_STATUS_OK)
|
||||
T_FAIL("notify_check return value (%d) != NOTIFY_STATUS_OK", rv);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void sig_handler(int sig) {
|
||||
int status = check();
|
||||
|
||||
// Only continue if handler was called from notification system
|
||||
if(status < 1)
|
||||
return;
|
||||
|
||||
if(handled != UNHANDLED)
|
||||
T_FAIL("handled (%d) was not reset to UNHANDLED as expected.", handled);
|
||||
|
||||
handled = HANDLED;
|
||||
}
|
||||
|
||||
void sig_setup() {
|
||||
// Register our signal handler
|
||||
signal(SIGINFO, sig_handler);
|
||||
}
|
||||
|
||||
void sig_cleanup() {
|
||||
// Register our signal handler
|
||||
signal(SIGINFO, SIG_DFL);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
int n_check;
|
||||
|
||||
// Setup our signal handler
|
||||
sig_setup();
|
||||
|
||||
// Register with notification system
|
||||
notify_register_signal(KEY, SIGINFO, &n_token);
|
||||
|
||||
n_check = check();
|
||||
if(n_check != 1)
|
||||
T_FAIL("notify_check failed to return 1 after initial registration.");
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
// Clean up our signal handler
|
||||
sig_cleanup();
|
||||
|
||||
notify_cancel(n_token);
|
||||
}
|
||||
|
||||
T_DECL(notify_register_signal_1,
|
||||
"Basic test to confirm that notify_register_signal works.",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
sig_setup();
|
||||
|
||||
T_LOG("Registering for signal based notification.");
|
||||
|
||||
// Register with notification system
|
||||
notify_register_signal(KEY, SIGINFO, &n_token);
|
||||
|
||||
post_notification("Ensure notifications are being handled properly.", 1);
|
||||
|
||||
sig_cleanup();
|
||||
}
|
||||
|
||||
T_DECL(notify_register_signal_2,
|
||||
"Test that notify_check handles signal notifications properly.",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
int n_check;
|
||||
|
||||
setup();
|
||||
|
||||
// Send UNIX style signal
|
||||
kill(getpid(),SIGINFO);
|
||||
T_EXPECT_EQ(handled, UNHANDLED,
|
||||
"handled (%d) remains unhandled, as expected.", handled);
|
||||
|
||||
post_notification("Sighandler notification after kill()", 1);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
T_DECL(notify_register_signal_3,
|
||||
"Test that notify_resume and notify_suspend handle signal notifications properly.",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
int i, n_check;
|
||||
uint32_t rv;
|
||||
|
||||
setup();
|
||||
|
||||
post_notification("Ensure notifications are being handled properly.", 1);
|
||||
|
||||
rv = notify_suspend(n_token);
|
||||
T_EXPECT_EQ(rv, NOTIFY_STATUS_OK,
|
||||
"notify_suspend rv (%d) != NOTIFY_STATUS_OK", rv);
|
||||
|
||||
for(i=0; i<3; i++) {
|
||||
post_notification("Suspended notification", 0);
|
||||
T_EXPECT_EQ(handled, UNHANDLED,
|
||||
"handled (%d) remains unhandled, as expected.", handled);
|
||||
}
|
||||
|
||||
// Returns NOTIFY_STATUS_FAILED. Leave off for now.
|
||||
//rv = notify_resume(n_token);
|
||||
//T_EXPECT_EQ(rv, NOTIFY_STATUS_OK,
|
||||
// "notify_resume rv != NOTIFY_STATUS_OK");
|
||||
//T_EXPECT_EQ(handled, HANDLED,
|
||||
// "handled has been handed for suspended notifications");
|
||||
|
||||
cleanup();
|
||||
}
|
67
tests/notify_sigusr.c
Normal file
67
tests/notify_sigusr.c
Normal file
@ -0,0 +1,67 @@
|
||||
#include <stdlib.h>
|
||||
#include <notify.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <darwintest.h>
|
||||
#include <signal.h>
|
||||
#include "../libnotify.h"
|
||||
|
||||
T_DECL(notify_sigusr, "Make sure SIGUSR{1,2} dumps status",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META_ASROOT(YES))
|
||||
{
|
||||
int v_token, rc;
|
||||
pid_t pid;
|
||||
uint64_t state;
|
||||
|
||||
T_LOG("Grab the current instance pid & version");
|
||||
{
|
||||
rc = notify_register_check(NOTIFY_IPC_VERSION_NAME, &v_token);
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "register_check(NOTIFY_IPC_VERSION_NAME)");
|
||||
|
||||
state = ~0ull;
|
||||
rc = notify_get_state(v_token, &state);
|
||||
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "notify_get_state(NOTIFY_IPC_VERSION_NAME)");
|
||||
|
||||
pid = (pid_t)(state >> 32);
|
||||
T_EXPECT_EQ((uint32_t)state, NOTIFY_IPC_VERSION, "IPC version should be set");
|
||||
}
|
||||
|
||||
char *status_file;
|
||||
asprintf(&status_file, "/var/run/notifyd_%u.status", pid);
|
||||
|
||||
T_LOG("Make sure SIGUSR1 works");
|
||||
{
|
||||
rc = kill(pid, SIGUSR1);
|
||||
T_ASSERT_POSIX_SUCCESS(rc, "Killing notifyd");
|
||||
|
||||
rc = -1;
|
||||
for (int i = 0; i < 10 && rc == -1; i++) {
|
||||
rc = unlink(status_file);
|
||||
if (rc == -1 && errno != ENOENT) {
|
||||
T_ASSERT_POSIX_SUCCESS(rc, "unlink(%s)", status_file);
|
||||
}
|
||||
usleep(100000); /* wait for .1s for notifyd to dump status */
|
||||
}
|
||||
T_ASSERT_POSIX_SUCCESS(rc, "unlink(%s)", status_file);
|
||||
}
|
||||
|
||||
T_LOG("Make sure SIGUSR2 works");
|
||||
{
|
||||
rc = kill(pid, SIGUSR2);
|
||||
T_ASSERT_POSIX_SUCCESS(rc, "Killing notifyd");
|
||||
|
||||
rc = -1;
|
||||
for (int i = 0; i < 10 && rc == -1; i++) {
|
||||
rc = unlink(status_file);
|
||||
if (rc == -1 && errno != ENOENT) {
|
||||
T_ASSERT_POSIX_SUCCESS(rc, "unlink(%s)", status_file);
|
||||
}
|
||||
usleep(100000); /* wait for .1s for notifyd to dump status */
|
||||
}
|
||||
T_ASSERT_POSIX_SUCCESS(rc, "unlink(%s)", status_file);
|
||||
}
|
||||
|
||||
free(status_file);
|
||||
}
|
65
tests/notify_suspend.c
Normal file
65
tests/notify_suspend.c
Normal file
@ -0,0 +1,65 @@
|
||||
//
|
||||
// notify_suspend.c
|
||||
// Libnotify
|
||||
//
|
||||
// Created by Brycen Wershing on 10/16/19.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <notify.h>
|
||||
#include <darwintest.h>
|
||||
|
||||
T_DECL(notify_suspend,
|
||||
"notify suspend registration test",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
__block bool suspendedToggle = false;
|
||||
__block bool notSuspendedToggle = false;
|
||||
int status;
|
||||
int suspendToken, noSuspendToken;
|
||||
const char *name = "com.apple.test.suspend";
|
||||
dispatch_queue_t queue = dispatch_queue_create("Test Q", NULL);
|
||||
|
||||
status = notify_register_dispatch(name, &suspendToken, queue, ^(__unused int token){
|
||||
suspendedToggle = true;
|
||||
});
|
||||
T_ASSERT_EQ(status, NOTIFY_STATUS_OK, "Register suspend token");
|
||||
|
||||
status = notify_register_dispatch(name, &noSuspendToken, queue, ^(__unused int token){
|
||||
notSuspendedToggle = true;
|
||||
});
|
||||
T_ASSERT_EQ(status, NOTIFY_STATUS_OK, "Register no-suspend token");
|
||||
|
||||
sleep(1);
|
||||
|
||||
T_ASSERT_EQ(suspendedToggle, false, "check suspend token before posts");
|
||||
T_ASSERT_EQ(notSuspendedToggle, false, "check no-suspend token before posts");
|
||||
|
||||
notify_suspend(suspendToken);
|
||||
notify_post(name);
|
||||
sleep(1);
|
||||
|
||||
T_ASSERT_EQ(suspendedToggle, false, "check suspend token after post");
|
||||
T_ASSERT_EQ(notSuspendedToggle, true, "check no-suspend token after post");
|
||||
|
||||
suspendedToggle = false;
|
||||
notSuspendedToggle = false;
|
||||
notify_resume(suspendToken);
|
||||
sleep(1);
|
||||
|
||||
T_ASSERT_EQ(suspendedToggle, true, "check suspend token after resume");
|
||||
T_ASSERT_EQ(notSuspendedToggle, false, "check no-suspend token after resume");
|
||||
|
||||
notify_post(name);
|
||||
sleep(1);
|
||||
|
||||
T_ASSERT_EQ(suspendedToggle, true, "check suspend token after final post");
|
||||
T_ASSERT_EQ(notSuspendedToggle, true, "check no-suspend token after final post");
|
||||
|
||||
T_PASS("Test complete");
|
||||
}
|
||||
|
102
tests/notify_test_helper.c
Normal file
102
tests/notify_test_helper.c
Normal file
@ -0,0 +1,102 @@
|
||||
//
|
||||
// notify_exec_helper.c
|
||||
// darwintests
|
||||
//
|
||||
// Created by Brycen Wershing on 2/10/20.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <notify.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
extern char **environ;
|
||||
|
||||
#define KEY "com.apple.notify.test"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
printf("In notify_test_helper\n");
|
||||
|
||||
uint32_t rc;
|
||||
int c_token, d_token;
|
||||
int check;
|
||||
__block bool dispatch_called = false;
|
||||
|
||||
dispatch_queue_t dq = dispatch_queue_create_with_target("q", NULL, NULL);
|
||||
|
||||
rc = notify_register_check(KEY, &c_token);
|
||||
if (rc != NOTIFY_STATUS_OK)
|
||||
{
|
||||
return 51;
|
||||
}
|
||||
|
||||
notify_check(c_token, &check);
|
||||
if (check != 1) {
|
||||
return 52;
|
||||
}
|
||||
notify_check(c_token, &check);
|
||||
if (check != 0) {
|
||||
return 53;
|
||||
}
|
||||
|
||||
rc = notify_register_dispatch(KEY, &d_token, dq, ^(int token){
|
||||
dispatch_called = true;
|
||||
});
|
||||
if (rc != NOTIFY_STATUS_OK)
|
||||
{
|
||||
return 54;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
if (dispatch_called) {
|
||||
return 55;
|
||||
}
|
||||
|
||||
rc = notify_post(KEY);
|
||||
if (rc != NOTIFY_STATUS_OK)
|
||||
{
|
||||
return 56;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
notify_check(c_token, &check);
|
||||
if (check != 1) {
|
||||
return 57;
|
||||
}
|
||||
|
||||
if (!dispatch_called) {
|
||||
return 58;
|
||||
}
|
||||
|
||||
rc = notify_cancel(c_token);
|
||||
if (rc != NOTIFY_STATUS_OK)
|
||||
{
|
||||
return 59;
|
||||
}
|
||||
|
||||
rc = notify_cancel(d_token);
|
||||
if (rc != NOTIFY_STATUS_OK)
|
||||
{
|
||||
return 60;
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
printf("Calling exec again\n");
|
||||
|
||||
char *argv[2];
|
||||
argv[0] = "notify_test_helper";
|
||||
argv[1] = NULL;
|
||||
|
||||
execve("/AppleInternal/Tests/Libnotify/notify_test_helper" ,argv , environ);
|
||||
printf("execve failed with %d\n", errno);
|
||||
abort();
|
||||
}
|
||||
|
||||
printf("Succeeded!\n");
|
||||
|
||||
return 42;
|
||||
}
|
36
tests/parallel_register_cancel.c
Normal file
36
tests/parallel_register_cancel.c
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// parallel_register_cancel.c
|
||||
// Libnotify
|
||||
//
|
||||
|
||||
#include <darwintest.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <notify.h>
|
||||
#include <stdio.h>
|
||||
|
||||
T_DECL(parallel_register_cancel,
|
||||
"parallel register/cancel test",
|
||||
T_META("owner", "Core Darwin Daemons & Tools"),
|
||||
T_META("as_root", "false"))
|
||||
{
|
||||
dispatch_queue_t noteQueue = dispatch_queue_create("noteQ", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
|
||||
static int tokens[100000];
|
||||
dispatch_apply(100000, DISPATCH_APPLY_AUTO, ^(size_t i) {
|
||||
assert(notify_register_check("com.example.test", &tokens[i]) == NOTIFY_STATUS_OK);
|
||||
assert(notify_cancel(tokens[i]) == NOTIFY_STATUS_OK);
|
||||
assert(notify_register_dispatch("com.example.test", &tokens[i], noteQueue, ^(int i){}) == NOTIFY_STATUS_OK);
|
||||
assert(notify_cancel(tokens[i]) == NOTIFY_STATUS_OK);
|
||||
assert(notify_post("com.example.test") == NOTIFY_STATUS_OK);
|
||||
});
|
||||
|
||||
|
||||
dispatch_apply(100000, DISPATCH_APPLY_AUTO, ^(size_t i) {
|
||||
assert(notify_register_check("self.example.test", &tokens[i]) == NOTIFY_STATUS_OK);
|
||||
assert(notify_cancel(tokens[i]) == NOTIFY_STATUS_OK);
|
||||
assert(notify_register_dispatch("self.example.test", &tokens[i], noteQueue, ^(int i){}) == NOTIFY_STATUS_OK);
|
||||
assert(notify_cancel(tokens[i]) == NOTIFY_STATUS_OK);
|
||||
assert(notify_post("self.example.test") == NOTIFY_STATUS_OK);
|
||||
});
|
||||
|
||||
T_PASS("Success");
|
||||
}
|
259
tests/random_test.c
Normal file
259
tests/random_test.c
Normal file
@ -0,0 +1,259 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <notify.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
#define forever for(;;)
|
||||
|
||||
#define MAX_REG 1000
|
||||
#define QUIT 1000000
|
||||
|
||||
int token[MAX_REG];
|
||||
char *tname[MAX_REG];
|
||||
int nregs = 0;
|
||||
pid_t mypid;
|
||||
int scount = 0;
|
||||
uint64_t actions = 0;
|
||||
|
||||
uint32_t
|
||||
pick_token(uint32_t x)
|
||||
{
|
||||
uint32_t i, n;
|
||||
|
||||
if (nregs == 0) return MAX_REG;
|
||||
|
||||
i = (x / 100) % MAX_REG;
|
||||
for (n = 0; n < MAX_REG; n++)
|
||||
{
|
||||
if (token[i] >= 0) return i;
|
||||
i = (i + i) % MAX_REG;
|
||||
}
|
||||
|
||||
return MAX_REG;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
empty_token(uint32_t x)
|
||||
{
|
||||
uint32_t i, n;
|
||||
|
||||
if (nregs == MAX_REG) return MAX_REG;
|
||||
|
||||
i = (x / 100) % MAX_REG;
|
||||
for (n = 0; n < MAX_REG; n++)
|
||||
{
|
||||
if (token[i] < 0) return i;
|
||||
i = (i + i) % MAX_REG;
|
||||
}
|
||||
|
||||
return MAX_REG;
|
||||
}
|
||||
|
||||
char *
|
||||
random_name(uint32_t x)
|
||||
{
|
||||
char *s = NULL;
|
||||
asprintf(&s, "Random.Notify.Test.%u.%u", mypid, x);
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
do_something()
|
||||
{
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
scount++;
|
||||
if (actions >= QUIT)
|
||||
{
|
||||
printf("\nTest Complete\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ((scount % 100) == 0) printf("\n%20llu %10u ", actions, scount);
|
||||
}
|
||||
|
||||
/* 0 */
|
||||
void
|
||||
random_cancel(uint32_t x)
|
||||
{
|
||||
uint32_t i = pick_token(x);
|
||||
if (i >= MAX_REG) return;
|
||||
|
||||
notify_cancel(token[i]);
|
||||
free(tname[i]);
|
||||
tname[i] = NULL;
|
||||
token[i] = -1;
|
||||
|
||||
nregs--;
|
||||
}
|
||||
|
||||
/* 1 */
|
||||
void
|
||||
random_register_check(uint32_t x)
|
||||
{
|
||||
int t;
|
||||
uint32_t i = empty_token(x);
|
||||
if (i >= MAX_REG) return;
|
||||
|
||||
char *s = random_name(x);
|
||||
if (s == NULL) return;
|
||||
|
||||
if (notify_register_check(s, &t) == NOTIFY_STATUS_OK)
|
||||
{
|
||||
token[i] = t;
|
||||
tname[i] = s;
|
||||
nregs++;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* 2 */
|
||||
void
|
||||
random_register_dispatch(uint32_t x)
|
||||
{
|
||||
int t;
|
||||
uint32_t i = empty_token(x);
|
||||
if (i >= MAX_REG) return;
|
||||
|
||||
char *s = random_name(x);
|
||||
if (s == NULL) return;
|
||||
|
||||
if (notify_register_dispatch(s, &t, dispatch_get_main_queue(), ^(int x){ do_something(); }) == NOTIFY_STATUS_OK)
|
||||
{
|
||||
token[i] = t;
|
||||
tname[i] = s;
|
||||
nregs++;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* 3 */
|
||||
void
|
||||
random_register_plain(uint32_t x)
|
||||
{
|
||||
int t;
|
||||
uint32_t i = empty_token(x);
|
||||
if (i >= MAX_REG) return;
|
||||
|
||||
char *s = random_name(x);
|
||||
if (s == NULL) return;
|
||||
|
||||
if (notify_register_plain(s, &t) == NOTIFY_STATUS_OK)
|
||||
{
|
||||
token[i] = t;
|
||||
tname[i] = s;
|
||||
nregs++;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* 4 */
|
||||
void
|
||||
random_post(uint32_t x)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (0 == (x % 10))
|
||||
{
|
||||
char *s = random_name(x);
|
||||
notify_post(s);
|
||||
free(s);
|
||||
return;
|
||||
}
|
||||
|
||||
i = pick_token(x);
|
||||
if (i >= MAX_REG) return;
|
||||
|
||||
notify_post(tname[i]);
|
||||
}
|
||||
|
||||
/* 5 */
|
||||
void
|
||||
random_check(uint32_t x)
|
||||
{
|
||||
int c;
|
||||
uint32_t i = pick_token(x);
|
||||
if (i >= MAX_REG) return;
|
||||
|
||||
notify_check(token[i], &c);
|
||||
}
|
||||
|
||||
/* 6 */
|
||||
void
|
||||
random_get_state(uint32_t x)
|
||||
{
|
||||
uint64_t v;
|
||||
uint32_t i = pick_token(x);
|
||||
if (i >= MAX_REG) return;
|
||||
|
||||
notify_get_state(token[i], &v);
|
||||
}
|
||||
|
||||
/* 7 */
|
||||
void
|
||||
random_set_state(uint32_t x)
|
||||
{
|
||||
uint64_t v = x;
|
||||
uint32_t i = pick_token(x);
|
||||
if (i >= MAX_REG) return;
|
||||
|
||||
notify_set_state(token[i], v);
|
||||
}
|
||||
|
||||
void
|
||||
random_notify()
|
||||
{
|
||||
uint32_t x, act, nap;
|
||||
|
||||
forever
|
||||
{
|
||||
x = arc4random();
|
||||
nap = ((x / 10) % 10) * 1000;
|
||||
act = x % 8;
|
||||
|
||||
switch (act)
|
||||
{
|
||||
case 0: random_cancel(x); break;
|
||||
case 1: random_register_check(x); break;
|
||||
case 2: random_register_dispatch(x); break;
|
||||
case 3: random_register_plain(x); break;
|
||||
case 4: random_post(x); break;
|
||||
case 5: random_check(x); break;
|
||||
case 6: random_get_state(x); break;
|
||||
case 7: random_set_state(x); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
usleep(nap);
|
||||
|
||||
actions++;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < MAX_REG; i++) token[i] = -1;
|
||||
|
||||
// dispatch_queue_t randomq = dispatch_queue_create("Random Queue", NULL);
|
||||
dispatch_queue_t randomq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
mypid = getpid();
|
||||
|
||||
printf("%20u %10u ", 0, 0);
|
||||
dispatch_async(randomq, ^{ random_notify(); });
|
||||
dispatch_main();
|
||||
|
||||
return 0;
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
// Architectures
|
||||
SDKROOT = macosx.internal
|
||||
|
||||
ALWAYS_SEARCH_USER_PATHS = YES
|
||||
ALWAYS_SEARCH_USER_PATHS = NO
|
||||
HEADER_SEARCH_PATHS = $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders $(PROJECT_DIR)
|
||||
ARCHS = $(ARCHS_STANDARD_32_64_BIT)
|
||||
CODE_SIGN_IDENTITY = -
|
||||
@ -15,10 +15,10 @@ GCC_PREPROCESSOR_DEFINITIONS = __DARWIN_NON_CANCELABLE=1
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES
|
||||
GCC_WARN_UNUSED_VARIABLE = YES
|
||||
//GCC_WARN_64_TO_32_BIT_CONVERSION = YES
|
||||
//GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
|
||||
//GCC_WARN_ABOUT_RETURN_TYPE = YES
|
||||
OTHER_CFLAGS = -fno-exceptions -Weverything -Wno-reserved-id-macro -Wno-padded -Wno-sign-compare -Wno-used-but-marked-unused -Wno-undef -Wno-cast-qual -Wno-documentation -Wno-unused-macros -Wno-gnu
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES
|
||||
OTHER_CFLAGS = -fno-exceptions -Weverything -Wno-reserved-id-macro -Wno-padded -Wno-used-but-marked-unused -Wno-undef -Wno-cast-qual -Wno-unused-macros -Wno-gnu -Wno-fixed-enum-extension -Wno-c++98-compat -Wno-pedantic
|
||||
OTHER_CFLAGS_debug = -O0
|
||||
CURRENT_PROJECT_VERSION =
|
||||
CURRENT_PROJECT_VERSION = $(RC_ProjectSourceVersion)
|
||||
@ -31,3 +31,4 @@ NOTIFY_CONFIG = notify.conf.MacOSX
|
||||
NOTIFY_CONFIG[sdk=iphoneos*] = notify.conf.iPhone
|
||||
NOTIFY_CONFIG[sdk=tvos*] = notify.conf.iPhone
|
||||
NOTIFY_CONFIG[sdk=*simulator*] = notify.conf.iOSSimulator
|
||||
|
||||
|
0
xcodescripts/no-sim-man.sh
Normal file → Executable file
0
xcodescripts/no-sim-man.sh
Normal file → Executable file
@ -1,5 +0,0 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
if [[ "${PLATFORM_NAME}" =~ "simulator" ]]; then
|
||||
ln -s libsystem_notify.dylib ${DSTROOT}${INSTALL_PATH}/libnotify_sim.dylib
|
||||
fi
|
Loading…
Reference in New Issue
Block a user