gen/FreeBSD/seekdir.c freebsd lib/libc/gen/seekdir.c 74c1506b3359ee725c9031331908b717460830dc
gen/FreeBSD/telldir.c freebsd lib/libc/gen/telldir.c 74c1506b3359ee725c9031331908b717460830dc
net/inet_ntop.c freebsd lib/libc/inet/inet_ntop.c f0171d33b464dee5ac308f1d13ede2ddd9d030a7
+gen/FreeBSD/ualarm.c freebsd lib/libc/gen/ualarm.c 377f319c60f3033b874d9f2f5d1abfa4925d87c5
+stdlib/FreeBSD/strtonum.3 freebsd lib/libc/stdlib/strtonum.3 6e8f2d848769a398fecc80ef93840372e88ac7a8
+stdlib/FreeBSD/strtonum.c freebsd lib/libc/stdlib/strtonum.c 2db0fe8cf836ce66973bddba1140f9812a903a84
objects = {
/* Begin PBXAggregateTarget section */
+ 183CC700235E757700C13E68 /* Libc_collections */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 183CC703235E757700C13E68 /* Build configuration list for PBXAggregateTarget "Libc_collections" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 18177AC3236A36EB008CCFDE /* PBXTargetDependency */,
+ );
+ name = Libc_collections;
+ productName = Libc_collections;
+ };
+ 2B9F887D2301074E00771815 /* Libc_dyld */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 2B9F88802301074E00771815 /* Build configuration list for PBXAggregateTarget "Libc_dyld" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 2B9F888323011C2B00771815 /* PBXTargetDependency */,
+ );
+ name = Libc_dyld;
+ productName = Libc_dyld;
+ };
925E7FE619E8945900AC7889 /* Libc_tests */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 925E7FF919E8945A00AC7889 /* Build configuration list for PBXAggregateTarget "Libc_tests" */;
);
dependencies = (
E47E981722150F0A006E312E /* PBXTargetDependency */,
- E47E981922150F2C006E312E /* PBXTargetDependency */,
E47E981B22150F2F006E312E /* PBXTargetDependency */,
E47E981D22150F32006E312E /* PBXTargetDependency */,
);
147CDFDF1B7C233100831EC6 /* clock_gettime.c in Sources */ = {isa = PBXBuildFile; fileRef = 147CDFD01B7C14FA00831EC6 /* clock_gettime.c */; };
147CDFE01B7C233200831EC6 /* clock_gettime.c in Sources */ = {isa = PBXBuildFile; fileRef = 147CDFD01B7C14FA00831EC6 /* clock_gettime.c */; };
147CDFE11B7C233300831EC6 /* clock_gettime.c in Sources */ = {isa = PBXBuildFile; fileRef = 147CDFD01B7C14FA00831EC6 /* clock_gettime.c */; };
+ 18177ABE236A351B008CCFDE /* _collections_map.h in Headers */ = {isa = PBXBuildFile; fileRef = 18177A84236A0EBC008CCFDE /* _collections_map.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 18177ABF236A351B008CCFDE /* collections_map.h in Headers */ = {isa = PBXBuildFile; fileRef = 18177A85236A0EBC008CCFDE /* collections_map.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 18177AC0236A351B008CCFDE /* collections.h in Headers */ = {isa = PBXBuildFile; fileRef = 18177A83236A0EBB008CCFDE /* collections.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 18177AC1236A3525008CCFDE /* collections_map.c in Sources */ = {isa = PBXBuildFile; fileRef = 18177A81236A0EB3008CCFDE /* collections_map.c */; };
+ 18B5085B237CF7090058A52D /* _collections_map.in.h in Headers */ = {isa = PBXBuildFile; fileRef = 18B5085A237CF3A30058A52D /* _collections_map.in.h */; settings = {ATTRIBUTES = (Private, ); }; };
2DF67CDE184F9CBE00B83A3D /* debug_private.c in Sources */ = {isa = PBXBuildFile; fileRef = 2DF67CDD184F9CBE00B83A3D /* debug_private.c */; };
2DF67CDF184F9CBE00B83A3D /* debug_private.c in Sources */ = {isa = PBXBuildFile; fileRef = 2DF67CDD184F9CBE00B83A3D /* debug_private.c */; };
2DF67CE0184F9CBE00B83A3D /* debug_private.c in Sources */ = {isa = PBXBuildFile; fileRef = 2DF67CDD184F9CBE00B83A3D /* debug_private.c */; };
928BD1081D76073600EC01FC /* timingsafe_bcmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 928BD0FE1D7606EA00EC01FC /* timingsafe_bcmp.c */; };
92ABC7E91D375FC2000DF880 /* compatibility_hacks.c in Sources */ = {isa = PBXBuildFile; fileRef = 92ABC7E81D375FC2000DF880 /* compatibility_hacks.c */; };
92D763E01EA6DA3A001467FC /* dirstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 92D763DC1EA6D9FB001467FC /* dirstat.c */; };
+ A5913A6623A47C570055A220 /* subsystem.c in Sources */ = {isa = PBXBuildFile; fileRef = A5BF59BE23A20A6900B1FADA /* subsystem.c */; };
+ A5913A6723A47C630055A220 /* subsystem.c in Sources */ = {isa = PBXBuildFile; fileRef = A5BF59BE23A20A6900B1FADA /* subsystem.c */; };
+ A5913A6823A47C820055A220 /* subsystem.c in Sources */ = {isa = PBXBuildFile; fileRef = A5BF59BE23A20A6900B1FADA /* subsystem.c */; };
+ A5913A6923A47C820055A220 /* subsystem.c in Sources */ = {isa = PBXBuildFile; fileRef = A5BF59BE23A20A6900B1FADA /* subsystem.c */; };
B10BC41C14338AEB005E4366 /* regcomp.c in Sources */ = {isa = PBXBuildFile; fileRef = B122F2B11432B95B00AF95D0 /* regcomp.c */; settings = {COMPILER_FLAGS = "-DHAVE_CONFIG_H -I$(SRCROOT)/regex/TRE -I$(SRCROOT)/regex/FreeBSD"; }; };
B122F2C71432B95B00AF95D0 /* regcomp.c in Sources */ = {isa = PBXBuildFile; fileRef = B122F2B11432B95B00AF95D0 /* regcomp.c */; };
B122F2C91432B95B00AF95D0 /* regexec.c in Sources */ = {isa = PBXBuildFile; fileRef = B122F2B21432B95B00AF95D0 /* regexec.c */; };
C0E345DC1C582ECB00E749C2 /* libFreeBSD.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C9257ED0138E1B5000B3107C /* libFreeBSD.a */; };
C0E345DD1C582ECB00E749C2 /* libvCancelable.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C9D94360138EC3E300FB7ACC /* libvCancelable.a */; };
C0E345DE1C582ECB00E749C2 /* libTRE.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B122F2AD1432B8E600AF95D0 /* libTRE.a */; };
+ C198002523F5C4FF004D70D5 /* strtonum.c in Sources */ = {isa = PBXBuildFile; fileRef = C198002323F5C4E1004D70D5 /* strtonum.c */; };
+ C198002623F5C4FF004D70D5 /* strtonum.c in Sources */ = {isa = PBXBuildFile; fileRef = C198002323F5C4E1004D70D5 /* strtonum.c */; };
+ C198002723F5C500004D70D5 /* strtonum.c in Sources */ = {isa = PBXBuildFile; fileRef = C198002323F5C4E1004D70D5 /* strtonum.c */; };
+ C198002823F5C500004D70D5 /* strtonum.c in Sources */ = {isa = PBXBuildFile; fileRef = C198002323F5C4E1004D70D5 /* strtonum.c */; };
+ C198002923F5C502004D70D5 /* strtonum.c in Sources */ = {isa = PBXBuildFile; fileRef = C198002323F5C4E1004D70D5 /* strtonum.c */; };
+ C198002A23F5C502004D70D5 /* strtonum.c in Sources */ = {isa = PBXBuildFile; fileRef = C198002323F5C4E1004D70D5 /* strtonum.c */; };
+ C198002B23F5C502004D70D5 /* strtonum.c in Sources */ = {isa = PBXBuildFile; fileRef = C198002323F5C4E1004D70D5 /* strtonum.c */; };
+ C198002C23F5C503004D70D5 /* strtonum.c in Sources */ = {isa = PBXBuildFile; fileRef = C198002323F5C4E1004D70D5 /* strtonum.c */; };
+ C198002D23F5C504004D70D5 /* strtonum.c in Sources */ = {isa = PBXBuildFile; fileRef = C198002323F5C4E1004D70D5 /* strtonum.c */; };
+ C198002E23F5C504004D70D5 /* strtonum.c in Sources */ = {isa = PBXBuildFile; fileRef = C198002323F5C4E1004D70D5 /* strtonum.c */; };
C9257ED5138E1C2E00B3107C /* creat.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B535F8138D9E980028D27C /* creat.c */; };
C9257ED6138E1C2E00B3107C /* gethostid.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B535FC138D9E980028D27C /* gethostid.c */; };
C9257ED7138E1C2E00B3107C /* getwd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B535FE138D9E980028D27C /* getwd.c */; };
C9FA334C138E4D040089A94B /* qsort_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b.c */; };
C9FA334D138E4D0C0089A94B /* strfmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB2138D9E9A0028D27C /* strfmon.c */; };
E408425B20B585BF00CC87A7 /* forceLibcToBuild.c in Sources */ = {isa = PBXBuildFile; fileRef = C9D9432A138DB72000FB7ACC /* forceLibcToBuild.c */; };
+ F749336D240DBC2000B709CC /* boot_mode_private.h in Headers */ = {isa = PBXBuildFile; fileRef = F749336C240DBBB100B709CC /* boot_mode_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
FC2ED610157D4BE80098EC69 /* inet_ntop.c in Sources */ = {isa = PBXBuildFile; fileRef = FC2ED60E157D4BE70098EC69 /* inet_ntop.c */; };
FC2ED611157D4BE80098EC69 /* inet_ntop.c in Sources */ = {isa = PBXBuildFile; fileRef = FC2ED60E157D4BE70098EC69 /* inet_ntop.c */; };
FC2ED612157D4BE80098EC69 /* inet_ntop.c in Sources */ = {isa = PBXBuildFile; fileRef = FC2ED60E157D4BE70098EC69 /* inet_ntop.c */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
+ 18177AC2236A36EB008CCFDE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C9B53597138D9A690028D27C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 18177AB9236A350B008CCFDE;
+ remoteInfo = libsystem_collections;
+ };
+ 2B9F888223011C2B00771815 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C9B53597138D9A690028D27C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C942102D13900C8A004BA536;
+ remoteInfo = libc_dyld;
+ };
3F51211616C318EB00AFB431 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C9B53597138D9A690028D27C /* Project object */;
remoteGlobalIDString = C9D9432E138DB73300FB7ACC;
remoteInfo = libsystem_c.dylib;
};
- E47E981822150F2C006E312E /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = C9B53597138D9A690028D27C /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = C942102D13900C8A004BA536;
- remoteInfo = libc_dyld;
- };
E47E981A22150F2F006E312E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C9B53597138D9A690028D27C /* Project object */;
/* Begin PBXFileReference section */
147CDFCF1B7C14FA00831EC6 /* clock_gettime.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = clock_gettime.3; sourceTree = "<group>"; };
147CDFD01B7C14FA00831EC6 /* clock_gettime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = clock_gettime.c; sourceTree = "<group>"; };
+ 18177A7C236A0DF0008CCFDE /* collections.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = collections.xcconfig; sourceTree = "<group>"; };
+ 18177A81236A0EB3008CCFDE /* collections_map.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = collections_map.c; sourceTree = "<group>"; };
+ 18177A82236A0EB3008CCFDE /* collections_map.in.c */ = {isa = PBXFileReference; indentWidth = 8; lastKnownFileType = sourcecode.c.c; path = collections_map.in.c; sourceTree = "<group>"; tabWidth = 8; };
+ 18177A83236A0EBB008CCFDE /* collections.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = collections.h; sourceTree = "<group>"; };
+ 18177A84236A0EBC008CCFDE /* _collections_map.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _collections_map.h; sourceTree = "<group>"; };
+ 18177A85236A0EBC008CCFDE /* collections_map.h */ = {isa = PBXFileReference; indentWidth = 8; lastKnownFileType = sourcecode.c.h; path = collections_map.h; sourceTree = "<group>"; tabWidth = 8; };
+ 18177ABA236A350B008CCFDE /* libsystem_collections.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_collections.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ 18B50859237CF0B70058A52D /* collections_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = collections_utilities.h; sourceTree = "<group>"; };
+ 18B5085A237CF3A30058A52D /* _collections_map.in.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _collections_map.in.h; sourceTree = "<group>"; };
2B514AB3203E4D9500641A4B /* thread_stack_pcs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = thread_stack_pcs.h; sourceTree = "<group>"; };
2DF67CDD184F9CBE00B83A3D /* debug_private.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = debug_private.c; path = os/debug_private.c; sourceTree = "<group>"; };
2DF67CE7184F9CD000B83A3D /* debug_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = debug_private.h; path = os/debug_private.h; sourceTree = "<group>"; };
3FA8F3091643AB4300D37078 /* strlcpy_chk.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = strlcpy_chk.c; sourceTree = "<group>"; };
3FB7E1B4146EF2E000843438 /* dirfd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dirfd.c; sourceTree = "<group>"; };
3FD14572171D42B300B7BAF5 /* bcopy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bcopy.c; sourceTree = "<group>"; };
- 3FF283231A4764240098AD2C /* sim-compat-symlink.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "sim-compat-symlink.sh"; sourceTree = "<group>"; };
4B0899B920460FAC001360A4 /* cleanup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cleanup.h; sourceTree = "<group>"; };
4B09323321C9C088006063D6 /* mach_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_utils.h; sourceTree = "<group>"; };
4B151E0B1F8574B400F3F52F /* style.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = style.3; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.man; };
92D763DC1EA6D9FB001467FC /* dirstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dirstat.c; sourceTree = "<group>"; };
92D763E41EA6F887001467FC /* dirstat_collection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirstat_collection.h; sourceTree = "<group>"; };
92D763E51EA6F887001467FC /* dirstat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirstat.h; sourceTree = "<group>"; };
+ A5BF59BD23A20A6900B1FADA /* subsystem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = subsystem.h; sourceTree = "<group>"; };
+ A5BF59BE23A20A6900B1FADA /* subsystem.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = subsystem.c; sourceTree = "<group>"; };
B122F2AD1432B8E600AF95D0 /* libTRE.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTRE.a; sourceTree = BUILT_PRODUCTS_DIR; };
B122F2AF1432B95B00AF95D0 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
B122F2B11432B95B00AF95D0 /* regcomp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = regcomp.c; sourceTree = "<group>"; };
C0E343811C58299D00E749C2 /* skip_installhdrs.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = skip_installhdrs.sh; sourceTree = "<group>"; };
C0E345E21C582ECB00E749C2 /* libc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libc.a; sourceTree = BUILT_PRODUCTS_DIR; };
C0E345E31C58300F00E749C2 /* libc_static.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libc_static.xcconfig; sourceTree = "<group>"; };
+ C198002323F5C4E1004D70D5 /* strtonum.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = strtonum.c; path = stdlib/FreeBSD/strtonum.c; sourceTree = SOURCE_ROOT; };
+ C198002423F5C4E2004D70D5 /* strtonum.3 */ = {isa = PBXFileReference; lastKnownFileType = text; name = strtonum.3; path = stdlib/FreeBSD/strtonum.3; sourceTree = SOURCE_ROOT; };
C9194B4C140E3BC700BE0C3A /* build_linklists.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = build_linklists.sh; sourceTree = "<group>"; };
C9257ED0138E1B5000B3107C /* libFreeBSD.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFreeBSD.a; sourceTree = BUILT_PRODUCTS_DIR; };
C9258105138E2D3100B3107C /* libNetBSD.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libNetBSD.a; sourceTree = BUILT_PRODUCTS_DIR; };
C976616B138EF14100741512 /* generate_features.pl */ = {isa = PBXFileReference; lastKnownFileType = text.script.perl; path = generate_features.pl; sourceTree = "<group>"; };
C97A721C1517AF53005E1998 /* libc_eOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libc_eOS.a; sourceTree = BUILT_PRODUCTS_DIR; };
C9950E6A1390D2CA009863B6 /* headers.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = headers.sh; sourceTree = "<group>"; };
+ C99F922E23982C7D0068CA74 /* ErrnoErrors.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = ErrnoErrors.strings; sourceTree = "<group>"; };
C9A288A71ACDBA95004A33A7 /* Makefile.inc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.pascal; path = Makefile.inc; sourceTree = "<group>"; };
C9AE91AE1517CDAC00A2626C /* eos.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = eos.xcconfig; sourceTree = "<group>"; };
C9B535AE138D9E980028D27C /* APPLE_LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = APPLE_LICENSE; sourceTree = "<group>"; };
E464104C224C5F19001B23EF /* _ctype.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _ctype.h; sourceTree = "<group>"; };
E4A877A6174D82FB000DBB55 /* alias.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = alias.list; sourceTree = "<group>"; };
E4EDB7262227DF25006A8322 /* Makefile.inc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.pascal; path = Makefile.inc; sourceTree = "<group>"; };
+ F749336C240DBBB100B709CC /* boot_mode_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = boot_mode_private.h; path = os/boot_mode_private.h; sourceTree = "<group>"; };
FC2ED60E157D4BE70098EC69 /* inet_ntop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inet_ntop.c; sourceTree = "<group>"; };
FC2ED60F157D4BE70098EC69 /* inet_pton.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inet_pton.c; sourceTree = "<group>"; };
FC2ED623157D4DA90098EC69 /* inet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inet.h; sourceTree = "<group>"; };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 18177A7E236A0E73008CCFDE /* collections */ = {
+ isa = PBXGroup;
+ children = (
+ 18177A80236A0E8F008CCFDE /* Source */,
+ 18177A7F236A0E88008CCFDE /* PublicHeader */,
+ );
+ path = collections;
+ sourceTree = "<group>";
+ };
+ 18177A7F236A0E88008CCFDE /* PublicHeader */ = {
+ isa = PBXGroup;
+ children = (
+ 18177A84236A0EBC008CCFDE /* _collections_map.h */,
+ 18B5085A237CF3A30058A52D /* _collections_map.in.h */,
+ 18177A85236A0EBC008CCFDE /* collections_map.h */,
+ 18177A83236A0EBB008CCFDE /* collections.h */,
+ );
+ path = PublicHeader;
+ sourceTree = "<group>";
+ };
+ 18177A80236A0E8F008CCFDE /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 18177A81236A0EB3008CCFDE /* collections_map.c */,
+ 18177A82236A0EB3008CCFDE /* collections_map.in.c */,
+ 18B50859237CF0B70058A52D /* collections_utilities.h */,
+ );
+ path = Source;
+ sourceTree = "<group>";
+ };
3F18DE1E162A732C008B15AC /* NetBSD */ = {
isa = PBXGroup;
children = (
4B2C64A015519B0500342BFA /* os */ = {
isa = PBXGroup;
children = (
+ F749336C240DBBB100B709CC /* boot_mode_private.h */,
4B782978208926A70070E1FF /* api.h */,
4B8A6F3121C99A0E00D00D67 /* linker_set.h */,
926F73991E03E8D6001E049D /* variant_private.h */,
children = (
C9B535AE138D9E980028D27C /* APPLE_LICENSE */,
C9B535AF138D9E980028D27C /* arm */,
+ 18177A7E236A0E73008CCFDE /* collections */,
C9B535F5138D9E980028D27C /* compat-43 */,
C9B53612138D9E980028D27C /* darwin */,
C9B5361D138D9E980028D27C /* db */,
3F5120F116C3174300AFB431 /* libFortifySource.a */,
C0E345E21C582ECB00E749C2 /* libc.a */,
926F73921E03E2A3001E049D /* libsystem_darwin.dylib */,
+ 18177ABA236A350B008CCFDE /* libsystem_collections.dylib */,
);
name = Products;
sourceTree = "<group>";
C9B53612138D9E980028D27C /* darwin */ = {
isa = PBXGroup;
children = (
+ C99F922E23982C7D0068CA74 /* ErrnoErrors.strings */,
+ A5BF59BD23A20A6900B1FADA /* subsystem.h */,
+ A5BF59BE23A20A6900B1FADA /* subsystem.c */,
C9ECE2761950E384008E8672 /* atexit_receipt.c */,
92ABC7E81D375FC2000DF880 /* compatibility_hacks.c */,
C9D9432A138DB72000FB7ACC /* forceLibcToBuild.c */,
C9B53D55138D9E9A0028D27C /* strstr.3 */,
C9B53D58138D9E9A0028D27C /* strtok.3 */,
C9B53D5A138D9E9A0028D27C /* strtok.c */,
+ C198002423F5C4E2004D70D5 /* strtonum.3 */,
+ C198002323F5C4E1004D70D5 /* strtonum.c */,
C9B53D5B138D9E9A0028D27C /* strxfrm.3 */,
C9B53D5D138D9E9A0028D27C /* strxfrm.c */,
C9B53D5F138D9E9A0028D27C /* swab.3 */,
C9C2A946138DF66900287F00 /* xcodescripts */ = {
isa = PBXGroup;
children = (
+ 18177A7C236A0DF0008CCFDE /* collections.xcconfig */,
E4A877A6174D82FB000DBB55 /* alias.list */,
C9C2A948138DF7DD00287F00 /* libc.xcconfig */,
C9766153138ECF0000741512 /* variants.xcconfig */,
C9B53D92138D9E9A0028D27C /* strip-header.ed */,
C965CBF4143BC1BF003912CE /* force_libc_to_build.sh */,
C93D6150143D31E300EB9023 /* sanitise_headers.sh */,
- 3FF283231A4764240098AD2C /* sim-compat-symlink.sh */,
C0E343811C58299D00E749C2 /* skip_installhdrs.sh */,
);
path = xcodescripts;
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
+ 18177AB6236A350B008CCFDE /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 18177ABE236A351B008CCFDE /* _collections_map.h in Headers */,
+ 18177ABF236A351B008CCFDE /* collections_map.h in Headers */,
+ 18177AC0236A351B008CCFDE /* collections.h in Headers */,
+ 18B5085B237CF7090058A52D /* _collections_map.in.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
926F73901E03E2A3001E049D /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
4B2D551E231706F9003DAFCE /* tapi.h in Headers */,
4B69E81320800D47008D13D2 /* libdarwin_init.h in Headers */,
4B20DB54202B81A4005C2327 /* string.h in Headers */,
+ F749336D240DBC2000B709CC /* boot_mode_private.h in Headers */,
4B075C8E208BE9F200FD4F23 /* variant_private.h in Headers */,
4B4E643F2069E94A00C4D8D5 /* internal.h in Headers */,
);
/* End PBXLegacyTarget section */
/* Begin PBXNativeTarget section */
+ 18177AB9236A350B008CCFDE /* libsystem_collections */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 18177ABB236A350B008CCFDE /* Build configuration list for PBXNativeTarget "libsystem_collections" */;
+ buildPhases = (
+ 18177AB6236A350B008CCFDE /* Headers */,
+ 18177AB7236A350B008CCFDE /* Sources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libsystem_collections;
+ productName = libsystem_collections;
+ productReference = 18177ABA236A350B008CCFDE /* libsystem_collections.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
3F51206A16C3174300AFB431 /* FortifySource */ = {
isa = PBXNativeTarget;
buildConfigurationList = 3F5120EE16C3174300AFB431 /* Build configuration list for PBXNativeTarget "FortifySource" */;
C0E343901C582ECB00E749C2 /* Patch Headers */,
C0E343911C582ECB00E749C2 /* Sources */,
C0E345DA1C582ECB00E749C2 /* Frameworks */,
- C0E345E41C5830C200E749C2 /* Symlink libc.a to a loaderd path */,
);
buildRules = (
);
C9D9432B138DB73300FB7ACC /* Sources */,
C9D9432C138DB73300FB7ACC /* Frameworks */,
C942135B13905EB9004BA536 /* Install Manpages */,
+ C99F922D23982C410068CA74 /* Install CoreTypes Strings */,
C965CBF3143BBFF7003912CE /* Remove deps.c */,
C93D6152143D321000EB9023 /* Sanitise Headers (rdar://problem/10241868) */,
- 3FF283291A4764370098AD2C /* Simulator Build Compat Symlink */,
);
buildRules = (
);
attributes = {
LastUpgradeCheck = 1140;
TargetAttributes = {
+ 18177AB9236A350B008CCFDE = {
+ CreatedOnToolsVersion = 11.2;
+ ProvisioningStyle = Automatic;
+ };
+ 2B9F887D2301074E00771815 = {
+ CreatedOnToolsVersion = 11.0;
+ ProvisioningStyle = Automatic;
+ };
925E7FE619E8945900AC7889 = {
CreatedOnToolsVersion = 6.1;
};
E47E980E22150EAD006E312E /* Libc */,
926F739D1E046E55001E049D /* Libc_darwin */,
E47E981222150EBB006E312E /* Libc_driverkit */,
+ 2B9F887D2301074E00771815 /* Libc_dyld */,
+ 183CC700235E757700C13E68 /* Libc_collections */,
925E7FE619E8945900AC7889 /* Libc_tests */,
C9D9432E138DB73300FB7ACC /* libsystem_c.dylib */,
C942102D13900C8A004BA536 /* libc_dyld */,
C9EB326F138F75580075BB52 /* Variant_Inode32 */,
3F51206A16C3174300AFB431 /* FortifySource */,
926F73911E03E2A3001E049D /* libsystem_darwin.dylib */,
+ 18177AB9236A350B008CCFDE /* libsystem_collections */,
928F25D01BEACED7007B13C7 /* darwintests */,
);
};
shellScript = "mkdir -p ${TAPI_PUBLIC_HEADER_PATH}\n";
showEnvVarsInLog = 0;
};
- 3FF283291A4764370098AD2C /* Simulator Build Compat Symlink */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 8;
- files = (
- );
- inputPaths = (
- "$(SRCROOT)/xcodescripts/sim-compat-symlink.sh",
- );
- name = "Simulator Build Compat Symlink";
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 1;
- shellPath = /bin/bash;
- shellScript = ". \"${SCRIPT_INPUT_FILE_0}\"";
- showEnvVarsInLog = 0;
- };
9280EA241E5A5D6F007A6F58 /* Copy AppleFooVariant.plists */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = ". \"${SCRIPT_INPUT_FILE_0}\" /bin/ln -sf libc_dyld.a ${DSTROOT}${INSTALL_PATH}/libc.a";
+ shellScript = ". \"${SCRIPT_INPUT_FILE_0}\" /bin/ln -sf libc_dyld.a ${DSTROOT}${INSTALL_PATH}/libc.a\n";
showEnvVarsInLog = 0;
};
C0E3438E1C582ECB00E749C2 /* Build Link List */ = {
shellScript = "perl \"${SRCROOT}/xcodescripts/patch_headers_variants.pl\" \\\n \"${SDK_SYSTEM_FRAMEWORK_HEADERS}\" \\\n \"${DERIVED_FILES_DIR}/System.framework/Versions/B\"\n";
showEnvVarsInLog = 0;
};
- C0E345E41C5830C200E749C2 /* Symlink libc.a to a loaderd path */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 8;
- files = (
- );
- inputPaths = (
- "$(SRCROOT)/xcodescripts/skip_installhdrs.sh",
- );
- name = "Symlink libc.a to a loaderd path";
- outputPaths = (
- "${DSTROOT}/usr/local/lib/loaderd/libc.a",
- );
- runOnlyForDeploymentPostprocessing = 1;
- shellPath = /bin/sh;
- shellScript = ". \"${SCRIPT_INPUT_FILE_0}\" /bin/ln -sf ../../../../${INSTALL_PATH}/libc.a ${DSTROOT}/usr/local/lib/loaderd/libc.a";
- showEnvVarsInLog = 0;
- };
C9194B4B140E3A7100BE0C3A /* Build Link Lists */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/bash;
- shellScript = ". \"${SCRIPT_INPUT_FILE_0}\"";
+ shellScript = ". \"${SCRIPT_INPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
C942102E13900C8A004BA536 /* Generate libc-features.h */ = {
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "perl \"$SRCROOT/xcodescripts/generate_features.pl\"";
+ shellScript = "perl \"$SRCROOT/xcodescripts/generate_features.pl\"\n";
showEnvVarsInLog = 0;
};
C942103013900C8A004BA536 /* Patch Headers */ = {
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = "/bin/bash -e";
- shellScript = ". \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_INPUT_FILE_1}\"";
+ shellScript = ". \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_INPUT_FILE_1}\"\n";
showEnvVarsInLog = 0;
};
C95B7EDA138F3C55004311DA /* Generate libc-features.h */ = {
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/bin/bash -e";
- shellScript = ". \"${SCRIPT_INPUT_FILE_0}\"";
+ shellScript = ". \"${SCRIPT_INPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ C99F922D23982C410068CA74 /* Install CoreTypes Strings */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/xcodescripts/install_errorstrings.sh",
+ "$(SRCROOT)/darwin/ErrnoErrors.strings",
+ );
+ name = "Install CoreTypes Strings";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = "/bin/bash -e";
+ shellScript = ". \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_INPUT_FILE_1}\"\n";
showEnvVarsInLog = 0;
};
C9AE91C21517E17600A2626C /* Build Link List */ = {
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "perl \"$SRCROOT/xcodescripts/generate_features.pl\"";
+ shellScript = "perl \"$SRCROOT/xcodescripts/generate_features.pl\"\n";
showEnvVarsInLog = 0;
};
C9BD3C3E138F18B200B389FD /* Generate libc-features.h */ = {
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ 18177AB7236A350B008CCFDE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 18177AC1236A3525008CCFDE /* collections_map.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
3F51206C16C3174300AFB431 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
C0E344A51C582ECB00E749C2 /* sockatmark.c in Sources */,
C0E344A61C582ECB00E749C2 /* sourcefilter.c in Sources */,
C0E344A71C582ECB00E749C2 /* msgcat.c in Sources */,
+ C198002623F5C4FF004D70D5 /* strtonum.c in Sources */,
C0E344A81C582ECB00E749C2 /* acl.c in Sources */,
C0E344A91C582ECB00E749C2 /* acl_entry.c in Sources */,
C0E344AA1C582ECB00E749C2 /* acl_file.c in Sources */,
C0E345771C582ECB00E749C2 /* strspn.c in Sources */,
C0E345791C582ECB00E749C2 /* strtok.c in Sources */,
C0E3457A1C582ECB00E749C2 /* strxfrm.c in Sources */,
+ A5913A6823A47C820055A220 /* subsystem.c in Sources */,
C0E3457B1C582ECB00E749C2 /* swab.c in Sources */,
C0E3457C1C582ECB00E749C2 /* wcpcpy.c in Sources */,
C0E3457D1C582ECB00E749C2 /* wcpncpy.c in Sources */,
C9257FBC138E1CC000B3107C /* fputs.c in Sources */,
C9257FBD138E1CC000B3107C /* fputwc.c in Sources */,
C9257FBE138E1CC000B3107C /* fputws.c in Sources */,
+ C198002823F5C500004D70D5 /* strtonum.c in Sources */,
C9257FBF138E1CC000B3107C /* fread.c in Sources */,
C9257FC0138E1CC000B3107C /* freopen.c in Sources */,
C9257FC1138E1CC000B3107C /* fscanf.c in Sources */,
C942105B13900C8A004BA536 /* hash_buf.c in Sources */,
C942105C13900C8A004BA536 /* hash_func.c in Sources */,
C942105D13900C8A004BA536 /* hash_log2.c in Sources */,
+ C198002523F5C4FF004D70D5 /* strtonum.c in Sources */,
C942105E13900C8A004BA536 /* hash_page.c in Sources */,
C942105F13900C8A004BA536 /* ndbm.c in Sources */,
C942106013900C8A004BA536 /* mpool.c in Sources */,
C942129B13900C8A004BA536 /* stack_protector.c in Sources */,
C942129C13900C8A004BA536 /* openx_np.c in Sources */,
C942129D13900C8A004BA536 /* OSMemoryNotification.c in Sources */,
+ A5913A6623A47C570055A220 /* subsystem.c in Sources */,
C942129E13900C8A004BA536 /* OSThermalNotification.c in Sources */,
C942129F13900C8A004BA536 /* posix_spawn.c in Sources */,
C94212A013900C8A004BA536 /* semctl.c in Sources */,
C95B8060138F3C55004311DA /* fopen.c in Sources */,
C95B8061138F3C55004311DA /* fprintf.c in Sources */,
C95B8062138F3C55004311DA /* fpurge.c in Sources */,
+ C198002A23F5C502004D70D5 /* strtonum.c in Sources */,
C95B8063138F3C55004311DA /* fputc.c in Sources */,
C95B8064138F3C55004311DA /* fputs.c in Sources */,
C95B8065138F3C55004311DA /* fputwc.c in Sources */,
C95B830B138F52B0004311DA /* fopen.c in Sources */,
C95B830C138F52B0004311DA /* fprintf.c in Sources */,
C95B830D138F52B0004311DA /* fpurge.c in Sources */,
+ C198002B23F5C502004D70D5 /* strtonum.c in Sources */,
C95B830E138F52B0004311DA /* fputc.c in Sources */,
C95B830F138F52B0004311DA /* fputs.c in Sources */,
C95B8310138F52B0004311DA /* fputwc.c in Sources */,
C95B85B1138F53DB004311DA /* fopen.c in Sources */,
C95B85B2138F53DB004311DA /* fprintf.c in Sources */,
C95B85B3138F53DB004311DA /* fpurge.c in Sources */,
+ C198002C23F5C503004D70D5 /* strtonum.c in Sources */,
C95B85B4138F53DB004311DA /* fputc.c in Sources */,
C95B85B5138F53DB004311DA /* fputs.c in Sources */,
C95B85B6138F53DB004311DA /* fputwc.c in Sources */,
C97A70C71517AF53005E1998 /* acl_translate.c in Sources */,
C97A70D11517AF53005E1998 /* regerror.c in Sources */,
C97A70D21517AF53005E1998 /* chk_fail.c in Sources */,
+ C198002723F5C500004D70D5 /* strtonum.c in Sources */,
C97A70D31517AF53005E1998 /* memcpy_chk.c in Sources */,
C97A70D41517AF53005E1998 /* memmove_chk.c in Sources */,
C97A70D51517AF53005E1998 /* memset_chk.c in Sources */,
C97A71541517AF53005E1998 /* imaxabs.c in Sources */,
C97A71551517AF53005E1998 /* imaxdiv.c in Sources */,
C97A71561517AF53005E1998 /* insque.c in Sources */,
+ A5913A6923A47C820055A220 /* subsystem.c in Sources */,
C97A71571517AF53005E1998 /* labs.c in Sources */,
C97A71581517AF53005E1998 /* ldiv.c in Sources */,
C97A71591517AF53005E1998 /* llabs.c in Sources */,
C9A128A3138E0CD10003880A /* acl_flag.c in Sources */,
C9A128A4138E0CD10003880A /* acl_perm.c in Sources */,
C9A128A5138E0CD10003880A /* acl_translate.c in Sources */,
+ A5913A6723A47C630055A220 /* subsystem.c in Sources */,
C9A12929138E0EF00003880A /* getdate.c in Sources */,
C9A1292A138E0EF00003880A /* timezone_unix03.c in Sources */,
B1795373158B0E35008990E8 /* xprintf_all_in_one.c in Sources */,
C9766035138EC61A00741512 /* fopen.c in Sources */,
C9766036138EC61A00741512 /* fprintf.c in Sources */,
C9766037138EC61A00741512 /* fpurge.c in Sources */,
+ C198002923F5C502004D70D5 /* strtonum.c in Sources */,
C9766038138EC61A00741512 /* fputc.c in Sources */,
C9766039138EC61A00741512 /* fputs.c in Sources */,
C976603A138EC61A00741512 /* fputwc.c in Sources */,
C9EB315C138F6D880075BB52 /* ftell.c in Sources */,
C9EB315D138F6D880075BB52 /* funopen.c in Sources */,
C9EB315E138F6D880075BB52 /* fvwrite.c in Sources */,
+ C198002D23F5C504004D70D5 /* strtonum.c in Sources */,
C9EB315F138F6D880075BB52 /* fwalk.c in Sources */,
C9EB3160138F6D880075BB52 /* fwide.c in Sources */,
C9EB3161138F6D880075BB52 /* fwprintf.c in Sources */,
C9EB3403138F75580075BB52 /* ftell.c in Sources */,
C9EB3404138F75580075BB52 /* funopen.c in Sources */,
C9EB3405138F75580075BB52 /* fvwrite.c in Sources */,
+ C198002E23F5C504004D70D5 /* strtonum.c in Sources */,
C9EB3406138F75580075BB52 /* fwalk.c in Sources */,
C9EB3407138F75580075BB52 /* fwide.c in Sources */,
C9EB3408138F75580075BB52 /* fwprintf.c in Sources */,
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
+ 18177AC3236A36EB008CCFDE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 18177AB9236A350B008CCFDE /* libsystem_collections */;
+ targetProxy = 18177AC2236A36EB008CCFDE /* PBXContainerItemProxy */;
+ };
+ 2B9F888323011C2B00771815 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C942102D13900C8A004BA536 /* libc_dyld */;
+ targetProxy = 2B9F888223011C2B00771815 /* PBXContainerItemProxy */;
+ };
3F51211716C318EB00AFB431 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 3F51206A16C3174300AFB431 /* FortifySource */;
target = C9D9432E138DB73300FB7ACC /* libsystem_c.dylib */;
targetProxy = E47E981622150F0A006E312E /* PBXContainerItemProxy */;
};
- E47E981922150F2C006E312E /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = C942102D13900C8A004BA536 /* libc_dyld */;
- targetProxy = E47E981822150F2C006E312E /* PBXContainerItemProxy */;
- };
E47E981B22150F2F006E312E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C0E343831C582ECB00E749C2 /* libc_static */;
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
+ 18177ABC236A350B008CCFDE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 18177A7C236A0DF0008CCFDE /* collections.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ 18177ABD236A350B008CCFDE /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 18177A7C236A0DF0008CCFDE /* collections.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ 183CC704235E757700C13E68 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 183CC705235E757700C13E68 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 2B9F887E2301074E00771815 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 2B9F887F2301074E00771815 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
3F5120EF16C3174300AFB431 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = /usr/lib/system;
- LIBSYSTEM_DARWIN_LDFLAGS = "-all_load -nostdlib -L/usr/lib/system -umbrella System $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBM_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBC_LDFLAGS) $(LIBDISPATCH_LDFLAGS) $(LIBXPC_LDFLAGS) -lmacho -ldyld -Wl,-upward-lsystem_trace";
OTHER_LDFLAGS = "$(LIBSYSTEM_DARWIN_LDFLAGS)";
- OTHER_TAPI_FLAGS = "$(inherited) -extra-public-header $(SRCROOT)/libdarwin/h/dirstat.h -extra-public-header $(SRCROOT)/libdarwin/internal.h -DDARWIN_TAPI=1 -extra-public-header $(SRCROOT)/os/variant_private.h";
+ OTHER_TAPI_FLAGS = "$(inherited) -extra-public-header $(SRCROOT)/libdarwin/h/dirstat.h -extra-public-header $(SRCROOT)/libdarwin/tapi.h -DDARWIN_TAPI=1 -extra-public-header $(SRCROOT)/os/variant_private.h -extra-public-header $(SRCROOT)/os/api.h";
PRIVATE_HEADERS_FOLDER_PATH = "$(DARWIN_PRIVATE_HEADERS_FOLDER_PATH)";
PRODUCT_NAME = darwin;
SKIP_INSTALL = NO;
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = /usr/lib/system;
- LIBSYSTEM_DARWIN_LDFLAGS = "-all_load -nostdlib -L/usr/lib/system -umbrella System $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBM_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBC_LDFLAGS) $(LIBDISPATCH_LDFLAGS) $(LIBXPC_LDFLAGS) -lmacho -ldyld -Wl,-upward-lsystem_trace";
OTHER_LDFLAGS = "$(LIBSYSTEM_DARWIN_LDFLAGS)";
OTHER_TAPI_FLAGS = "$(inherited) -extra-public-header $(SRCROOT)/libdarwin/h/dirstat.h -extra-public-header $(SRCROOT)/libdarwin/tapi.h -DDARWIN_TAPI=1 -extra-public-header $(SRCROOT)/os/variant_private.h -extra-public-header $(SRCROOT)/os/api.h";
PRIVATE_HEADERS_FOLDER_PATH = "$(DARWIN_PRIVATE_HEADERS_FOLDER_PATH)";
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
- ONLY_ACTIVE_ARCH = YES;
+ ONLY_ACTIVE_ARCH = NO;
};
name = Debug;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
+ 18177ABB236A350B008CCFDE /* Build configuration list for PBXNativeTarget "libsystem_collections" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 18177ABC236A350B008CCFDE /* Debug */,
+ 18177ABD236A350B008CCFDE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 183CC703235E757700C13E68 /* Build configuration list for PBXAggregateTarget "Libc_collections" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 183CC704235E757700C13E68 /* Debug */,
+ 183CC705235E757700C13E68 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2B9F88802301074E00771815 /* Build configuration list for PBXAggregateTarget "Libc_dyld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2B9F887E2301074E00771815 /* Debug */,
+ 2B9F887F2301074E00771815 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
3F5120EE16C3174300AFB431 /* Build configuration list for PBXNativeTarget "FortifySource" */ = {
isa = XCConfigurationList;
buildConfigurations = (
--- /dev/null
+#
+# Selectable features for MacOSX
+#
+
+# Legacy *64 APIs
+FEATURE_LEGACY_64_APIS = 1
+
+# Legacy crt1.o environ support
+FEATURE_LEGACY_CRT1_ENVIRON = 1
+
+# Legacy rune APIs
+FEATURE_LEGACY_RUNE_APIS = 1
+
+# Legacy utmp APIs
+FEATURE_LEGACY_UTMP_APIS = 1
+
+# OSThermalNotification APIs
+FEATURE_THERM_NOTIFICATION_APIS = 1
+
+# No pre-1050 variants (should match sys/cdefs.h)
+FEATURE_ONLY_1050_VARIANTS = 0
+
+# No legacy variants (should match sys/cdefs.h)
+FEATURE_ONLY_UNIX_CONFORMANCE = 0
+
+# Only 64-bit ino_t (should match sys/cdefs.h)
+FEATURE_ONLY_64_BIT_INO_T = 0
+
+# Patch 3333969
+FEATURE_PATCH_3333969 = 1
+
+# Patch 3417676
+FEATURE_PATCH_3417676 = 1
+
+# plockstat dtrace support
+FEATURE_PLOCKSTAT = 1
+
+# Timezone change notification
+FEATURE_TIMEZONE_CHANGE_NOTIFICATION = 1
+
+# Extensible printf performance enhancement (uses more memory)
+FEATURE_XPRINTF_PERF = 1
+
+# Disable registration of specific signals (<rdar://problem/21952708>)
+# FEATURE_SIGNAL_RESTRICTION = 0
+
+# Enable 32-bit compilation in unistd.h (<rdar://problem/51818745>)
+# FEATURE_POSIX_ILP32_ALLOW = 0
FEATURE_THERM_NOTIFICATION_APIS = 1
# No pre-1050 variants (should match sys/cdefs.h)
-#FEATURE_ONLY_1050_VARIANTS = 1
+FEATURE_ONLY_1050_VARIANTS = 1
# No legacy variants (should match sys/cdefs.h)
-.if CURRENT_ARCH 64$
FEATURE_ONLY_UNIX_CONFORMANCE = 1
-.endif
# Only 64-bit ino_t (should match sys/cdefs.h)
-#FEATURE_ONLY_64_BIT_INO_T = 1
+FEATURE_ONLY_64_BIT_INO_T = 1
# Patch 3333969
FEATURE_PATCH_3333969 = 1
--- /dev/null
+#
+# Selectable features for MacOSX
+#
+
+# Legacy *64 APIs
+FEATURE_LEGACY_64_APIS = 1
+
+# Legacy crt1.o environ support
+FEATURE_LEGACY_CRT1_ENVIRON = 1
+
+# Legacy rune APIs
+FEATURE_LEGACY_RUNE_APIS = 1
+
+# Legacy utmp APIs
+FEATURE_LEGACY_UTMP_APIS = 1
+
+# OSThermalNotification APIs
+FEATURE_THERM_NOTIFICATION_APIS = 1
+
+# No pre-1050 variants (should match sys/cdefs.h)
+FEATURE_ONLY_1050_VARIANTS = 0
+
+# No legacy variants (should match sys/cdefs.h)
+FEATURE_ONLY_UNIX_CONFORMANCE = 1
+
+# Only 64-bit ino_t (should match sys/cdefs.h)
+FEATURE_ONLY_64_BIT_INO_T = 0
+
+# Patch 3333969
+FEATURE_PATCH_3333969 = 1
+
+# Patch 3417676
+FEATURE_PATCH_3417676 = 1
+
+# plockstat dtrace support
+FEATURE_PLOCKSTAT = 1
+
+# Timezone change notification
+FEATURE_TIMEZONE_CHANGE_NOTIFICATION = 1
+
+# Extensible printf performance enhancement (uses more memory)
+FEATURE_XPRINTF_PERF = 1
+
+# Disable registration of specific signals (<rdar://problem/21952708>)
+# FEATURE_SIGNAL_RESTRICTION = 0
+
+# Enable 32-bit compilation in unistd.h (<rdar://problem/51818745>)
+# FEATURE_POSIX_ILP32_ALLOW = 0
--- /dev/null
+/*
+* Copyright (c) 2019 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@
+*/
+
+#ifndef __OS_COLLECTIONS_MAP_H
+#define __OS_COLLECTIONS_MAP_H
+
+#include <os/collections_map.h>
+
+OS_ASSUME_NONNULL_BEGIN
+__BEGIN_DECLS
+
+#ifndef os_map_str_payload_handler_t
+typedef bool (^os_map_str_payload_handler_t) (const char *, void *);
+#endif
+
+#ifndef os_map_32_payload_handler_t
+typedef bool (^os_map_32_payload_handler_t) (uint32_t, void *);
+#endif
+
+#ifndef os_map_64_payload_handler_t
+typedef bool (^os_map_64_payload_handler_t) (uint64_t, void *);
+#endif
+
+#ifndef os_map_128_payload_handler_t
+typedef bool (^os_map_128_payload_handler_t) (os_map_128_key_t, void *);
+#endif
+
+OS_EXPORT
+const char *
+os_map_str_entry(os_map_str_t *m, const char *key);
+
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline const char * _Nullable
+os_map_entry(os_map_str_t *m, const char *key)
+{
+ return os_map_str_entry(m, key);
+}
+
+__END_DECLS
+OS_ASSUME_NONNULL_END
+
+#define IN_MAP(PREFIX, SUFFIX) PREFIX ## os_map_str ## SUFFIX
+#define os_map_key_t const char *
+#include "_collections_map.in.h"
+#undef IN_MAP
+#undef os_map_key_t
+
+#define IN_MAP(PREFIX, SUFFIX) PREFIX ## os_map_32 ## SUFFIX
+#define os_map_key_t uint32_t
+#include "_collections_map.in.h"
+#undef IN_MAP
+#undef os_map_key_t
+
+#define IN_MAP(PREFIX, SUFFIX) PREFIX ## os_map_64 ## SUFFIX
+#define os_map_key_t uint64_t
+#include "_collections_map.in.h"
+#undef IN_MAP
+#undef os_map_key_t
+
+#define IN_MAP(PREFIX, SUFFIX) PREFIX ## os_map_128 ## SUFFIX
+#define os_map_key_t os_map_128_key_t
+#include "_collections_map.in.h"
+#undef IN_MAP
+#undef os_map_key_t
+
+#endif /* __OS_COLLECTIONS_MAP_H */
--- /dev/null
+/*
+* Copyright (c) 2019 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 (mhe '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@
+*/
+
+OS_ASSUME_NONNULL_BEGIN
+__BEGIN_DECLS
+
+#define os_map_t IN_MAP(,_t)
+
+OS_EXPORT
+void
+IN_MAP(,_init)(os_map_t *m, os_map_config_t * _Nullable config,
+ int struct_version);
+
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void
+os_map_init(os_map_t *m, os_map_config_t * _Nullable config) {
+ IN_MAP(,_init)(m, config, OS_MAP_CONFIG_S_VERSION);
+}
+
+OS_EXPORT
+void
+IN_MAP(,_destroy)(os_map_t *m);
+
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void
+os_map_destroy(os_map_t *m) {
+ IN_MAP(,_destroy)(m);
+}
+
+OS_EXPORT
+void
+IN_MAP(,_insert)(os_map_t *m, os_map_key_t key, void *val);
+
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void
+os_map_insert(os_map_t *m, os_map_key_t key, void *val) {
+ IN_MAP(,_insert)(m, key, val);
+}
+
+OS_EXPORT
+void *
+IN_MAP(,_find)(os_map_t *m, os_map_key_t key);
+
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void * _Nullable
+os_map_find(os_map_t *m, os_map_key_t key) {
+ return IN_MAP(,_find)(m, key);
+}
+
+OS_EXPORT
+void *
+IN_MAP(,_delete)(os_map_t *m, os_map_key_t key);
+
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void * _Nullable
+os_map_delete(os_map_t *m, os_map_key_t key) {
+ return IN_MAP(,_delete)(m, key);
+}
+
+OS_EXPORT
+void
+IN_MAP(,_clear)(os_map_t *m,
+ OS_NOESCAPE IN_MAP(,_payload_handler_t) handler);
+
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void
+os_map_clear(os_map_t *m,
+ OS_NOESCAPE IN_MAP(,_payload_handler_t) handler) {
+ IN_MAP(,_clear)(m, handler);
+}
+
+OS_EXPORT
+size_t
+IN_MAP(,_count)(os_map_t *m);
+
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline size_t
+os_map_count(os_map_t *m) {
+ return IN_MAP(,_count)(m);
+}
+
+OS_EXPORT
+void
+IN_MAP(,_foreach)(os_map_t *m,
+ OS_NOESCAPE IN_MAP(,_payload_handler_t) handler);
+
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void
+os_map_foreach(os_map_t *m,
+ OS_NOESCAPE IN_MAP(,_payload_handler_t) handler) {
+ IN_MAP(,_foreach)(m, handler);
+}
+
+__END_DECLS
+OS_ASSUME_NONNULL_END
--- /dev/null
+/*
+* Copyright (c) 2019 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@
+*/
+
+#ifndef _OS_COLLECTIONS_H_
+#define _OS_COLLECTIONS_H_
+
+#include <os/collections_map.h>
+
+#endif // _OS_COLLECTIONS_H_
--- /dev/null
+/*
+* Copyright (c) 2019 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@
+*/
+
+#ifndef _OS_COLLECTIONS_MAP_H
+#define _OS_COLLECTIONS_MAP_H
+
+#include <os/base.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <TargetConditionals.h>
+#include <sys/types.h>
+
+OS_ASSUME_NONNULL_BEGIN
+
+struct os_map_config_s
+{
+ const char *name; // Only used when DEBUG is set
+ uint32_t initial_size; // If 0, default will be used
+};
+
+// Increment this when changing os_map_config_s
+#define OS_MAP_CONFIG_S_VERSION 1
+
+typedef struct os_map_config_s os_map_config_t;
+
+
+// *** HASH MAPS ***
+// Stores values for keys. Not safe for concurrent use.
+
+
+struct os_map_128_key_s {
+ uint64_t x[2];
+};
+
+typedef struct os_map_128_key_s os_map_128_key_t;
+
+#if TARGET_RT_64_BIT
+#define OPAQUE_MAP_SIZE 3
+#else
+#define OPAQUE_MAP_SIZE 4
+#endif
+
+struct _os_opaque_str_map_s {
+ void *data[OPAQUE_MAP_SIZE];
+};
+
+struct _os_opaque_32_map_s {
+ void *data[OPAQUE_MAP_SIZE];
+};
+
+struct _os_opaque_64_map_s {
+ void *data[OPAQUE_MAP_SIZE];
+};
+
+struct _os_opaque_128_map_s {
+ void *data[OPAQUE_MAP_SIZE];
+};
+
+// Map with string keys and void * values
+// Keys must be valid pointers.
+typedef struct _os_opaque_str_map_s os_map_str_t ;
+// Map with uint32_t keys and void * values
+typedef struct _os_opaque_32_map_s os_map_32_t ;
+// Map with uint64_t keys and void * values
+typedef struct _os_opaque_64_map_s os_map_64_t ;
+// Map with os_map_128_key_t keys and void * values
+typedef struct _os_opaque_128_map_s os_map_128_t ;
+
+/*!
+* @function os_map_init
+* Initialize a map.
+*
+* @param t
+* The table to initialize
+*
+* @param config
+* The configuration to use for this table
+*
+* @discussion
+* An initialized map will use additional memory which can be freed with
+* os_map_destroy.
+*/
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void
+os_map_init(os_map_64_t *m, os_map_config_t * _Nullable config);
+
+/*!
+* @function os_map_destroy
+* Destroy a map.
+*
+* @param t
+* The table to destroy.
+*
+* @discussion
+* This will free all memory used by the map, but will not take any action
+* on the keys/values that were in the map at the time.
+*/
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void
+os_map_destroy(os_map_64_t *m);
+
+/*!
+* @function os_map_insert
+* Insert an element into a map.
+*
+* @param t
+* The table to initialize
+*
+* @param key
+* The key to insert the value at
+*
+* @param val
+* The value to insert; cannot be NULL (use os_map_delete to remove entries)
+*
+* @discussion
+* This will insert an element into the map, growing the map if needed. Does not
+* support replacing an existing key, so inserting twice without a remove will
+* cause undefined behavior.
+*/
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void
+os_map_insert(os_map_64_t *m, uint64_t key, void *val);
+
+/*!
+* @function os_map_find
+* Find an element in a map.
+*
+* @param t
+* The map to search
+*
+* @param key
+* The key to search for
+*
+* @result
+* The value stored at key, or NULL if no value is present.
+*
+*/
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void * _Nullable
+os_map_find(os_map_64_t *m, uint64_t key);
+
+/*!
+* @function os_map_delete
+* Remove an element from a map.
+*
+* @param t
+* The map to remove the element from
+*
+* @param key
+* The key of the element to be removed
+*
+* @result
+* The value stored at key, or NULL if no value is present.
+*
+* @discussion
+* Has no effect if the key is not present
+*/
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void * _Nullable
+os_map_delete(os_map_64_t *m, uint64_t key);
+
+typedef bool (^os_map_64_payload_handler_t) (uint64_t, void *);
+
+/*!
+* @function os_map_clear
+* Removes all elements from a map.
+*
+* @param t
+* The map to remove the elements from
+*
+* @param handler
+* A handler that will be called for all elements in the table. Handler may be
+* NULL.
+*
+* @discussion
+* Has no effect if the key is not present
+*/
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void
+os_map_clear(os_map_64_t *m,
+ OS_NOESCAPE os_map_64_payload_handler_t _Nullable handler);
+
+/*!
+* @function os_map_count
+* Gets the number of items present in a map
+*
+* @param t
+* The map to get the count of
+*
+* @result
+* Returns the number of items present in the map
+*/
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline size_t
+os_map_count(os_map_64_t *m);
+
+/*!
+* @function os_map_foreach
+*Iterate over the key/value pairs in a map.
+*
+* @param t
+* The map to iterate over
+*
+* @param handler
+* The handler to call for each entry in the map.
+*
+* @discussion
+* Will invoke handler for each key/value pair in the map. Modifying the map
+* during this iteration is not permitted. The handler may be called on the
+* entries in any order.
+*/
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline void
+os_map_foreach(os_map_64_t *m,
+ OS_NOESCAPE os_map_64_payload_handler_t handler);
+
+/*!
+* @function os_map_entry
+* Gets the exact entry, if present, for a given key and NULL otherwise.
+*
+* @param t
+* The map to search
+*
+* @param key
+* The key to search for
+*
+* @discussion
+* Only available for os_map_str_t.
+* Gets the exact entry, if present, for a given key and NULL otherwise. So, for
+* two equal strings a, b where a != b. We guarentee that
+* os_map_entry(t, a) == os_map_entry(t, b)
+*/
+OS_OVERLOADABLE OS_ALWAYS_INLINE
+static inline const char *
+os_map_entry(os_map_str_t *m, const char *key);
+
+OS_ASSUME_NONNULL_END
+
+#include <os/_collections_map.h>
+
+#endif /* _OS_COLLECTIONS_MAP_H */
--- /dev/null
+/*
+* Copyright (c) 2019 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 <os/collections_map.h>
+
+#include <os/base_private.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+
+static inline bool
+os_map_str_key_equals(const char * a, const char *b)
+{
+ return a == b || strcmp(a, b) == 0;
+}
+
+static inline uint32_t
+os_map_str_hash(const char *key)
+{
+ uint32_t hash = 0;
+
+ for (; *key; key++) {
+ hash += (unsigned char)(*key);
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+
+ return hash;
+}
+
+static inline bool
+os_map_32_key_equals(uint32_t a, uint32_t b)
+{
+ return a == b;
+}
+
+static inline uint32_t
+os_map_32_hash(uint32_t x)
+{
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = (x >> 16) ^ x;
+ return (uint32_t)x;
+}
+
+static inline bool
+os_map_64_key_equals(uint64_t a, uint64_t b)
+{
+ return a == b;
+}
+
+static inline uint32_t
+os_map_64_hash(uint64_t key)
+{
+ return os_map_32_hash((uint32_t)key ^ (uint32_t)(key >> 32));
+}
+
+static inline bool
+os_map_128_key_equals(os_map_128_key_t a, os_map_128_key_t b)
+{
+ return a.x[0] == b.x[0] &&
+ a.x[1] == b.x[1];
+}
+
+static inline uint32_t
+os_map_128_hash(os_map_128_key_t key)
+{
+ return os_map_64_hash(key.x[0] ^ key.x[1]);
+}
+
+// The following symbols are required for each include of collections_map.in.c
+// IN_MAP(, _t)
+// EXAMPLE: os_map_64_t
+// The opaque representation of the map.
+// IN_MAP(, _hash)
+// EXAMPLE: os_map_64_hash
+// The default hash function for the map
+// IN_MAP(,_key_equals)
+// Example: os_map_64_key_equals
+// The equality check for this map
+
+#define IN_MAP(PREFIX, SUFFIX) PREFIX ## os_map_str ## SUFFIX
+#define os_map_key_t const char *
+#define MAP_SUPPORTS_ENTRY
+#include "collections_map.in.c"
+#undef IN_MAP
+#undef os_map_key_t
+#undef MAP_SUPPORTS_ENTRY
+
+#define IN_MAP(PREFIX, SUFFIX) PREFIX ## os_map_32 ## SUFFIX
+#define os_map_key_t uint32_t
+#include "collections_map.in.c"
+#undef IN_MAP
+#undef os_map_key_t
+
+#define IN_MAP(PREFIX, SUFFIX) PREFIX ## os_map_64 ## SUFFIX
+#define os_map_key_t uint64_t
+#include "collections_map.in.c"
+#undef IN_MAP
+#undef os_map_key_t
+
+#define IN_MAP(PREFIX, SUFFIX) PREFIX ## os_map_128 ## SUFFIX
+#define os_map_key_t os_map_128_key_t
+#include "collections_map.in.c"
+#undef IN_MAP
+#undef os_map_key_t
--- /dev/null
+/*
+* Copyright (c) 2019 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 <sys/types.h>
+
+#include "collections_utilities.h"
+
+// =========== Required per-type definitions ===========
+#define opaque_os_map_t IN_MAP(,_t)
+#define os_map_hash IN_MAP(,_hash)
+#define os_map_key_equals IN_MAP(,_key_equals)
+
+// =========== Helpers, defined only once for all different types ===========
+
+#ifndef _COLLETIONS_MAP_HELPERS_C
+#define _COLLETIONS_MAP_HELPERS_C
+
+
+#define _MAP_MAX_FILL_NUMER 4
+#define _MAP_MAX_FILL_DENOM 5
+#define _MAP_GROW_SHIFT_RATE 8
+#define _MAP_MIN_FILL_DENOM 8
+
+OS_ALWAYS_INLINE
+static inline uint32_t
+map_next(uint32_t i, uint32_t size)
+{
+ i++;
+ return i >= size ? 0 : i;
+}
+
+OS_ALWAYS_INLINE
+static inline uint32_t
+map_prev(uint32_t i, uint32_t size)
+{
+ return ((i != 0) ? i : size) - 1;
+}
+
+struct _os_map_internal_struct {
+ void *data;
+ uint32_t count;
+ uint32_t size;
+ uint16_t grow_shift;
+ uint16_t max_bucket_offset;
+ // Keys are at data; values are at (data + count * sizeof(keys))
+};
+
+#endif
+
+// =========== Helpers, defined per map ===========
+
+#define _os_map_t IN_MAP(_,_t)
+typedef struct _os_map_internal_struct _os_map_t;
+
+#define _os_map_data_segregated IN_MAP(_,_data_segregated)
+struct _os_map_data_segregated {
+ os_map_key_t *keys;
+ void **vals;
+};
+
+#define _os_map_data_ref_t IN_MAP(_,_data_ref_t)
+typedef struct _os_map_data_segregated _os_map_data_ref_t;
+
+#define _alloc_data IN_MAP(_,_alloc_data)
+
+static inline void *
+_alloc_data(uint32_t size)
+{
+ assert(size < UINT32_MAX);
+ void *result = calloc(size, sizeof(os_map_key_t) + sizeof(void *));
+ assert(result != NULL);
+ return result;
+}
+
+
+#define _get_data_ref IN_MAP(_,_get_data_ref)
+
+static inline void
+_get_data_ref(_os_map_t *m, _os_map_data_ref_t *data)
+{
+ data->keys = (os_map_key_t *)(m->data);
+ data->vals = (void *)(((char *)(m->data)) +
+ (m->size * sizeof(os_map_key_t)));
+}
+
+
+#define _free_data IN_MAP(_,_free_data)
+
+static inline void
+_free_data(_os_map_data_ref_t *data)
+{
+ free((void *)data->keys);
+}
+
+#define _get_key(data, i) data.keys[i]
+
+#define _get_val(data, i) data.vals[i]
+
+#define _set_key(data, i, key) data.keys[i] = key
+
+#define _set_val(data, i, val) data.vals[i] = val
+
+
+#define _os_map_bucket IN_MAP(_,_probe_bucket)
+
+static inline uint32_t
+_os_map_bucket(_os_map_t *m, os_map_key_t key)
+{
+ return os_map_hash(key) % m->size;
+}
+
+#define _os_map_bucket_offset IN_MAP(_,_bucket_offset)
+
+static inline uint32_t
+_os_map_bucket_offset(_os_map_t *m, os_map_key_t key, uint32_t i)
+{
+ uint32_t bucket = _os_map_bucket(m, key);
+ return (i - bucket) % m->size;
+}
+
+#ifdef DEBUG
+
+#define _get_next_offset IN_MAP(_,_verify_next_offset)
+
+inline int64_t
+_get_next_offset(_os_map_t *m, _os_map_data_ref_t data,
+ uint32_t index, uint32_t size)
+{
+ uint32_t next_index = map_next(index, size);
+
+ if (_get_val(data, next_index) == NULL) {
+ return -1;
+ }
+
+ return _os_map_bucket_offset(m, _get_key(data, next_index),
+ next_index);
+}
+
+#define _os_map_verify IN_MAP(_,_verify)
+
+void
+_os_map_verify(_os_map_t *m)
+{
+ _os_map_data_ref_t data;
+ _get_data_ref(m, &data);
+
+ int64_t current_bucket_offset;
+ int64_t next_bucket_offset;
+ if (_get_val(data, 0) == NULL) {
+ next_bucket_offset = -1;
+ } else {
+ next_bucket_offset = _os_map_bucket_offset(m,
+ _get_key(data, 0), 0);
+ }
+
+ uint32_t size = m->size;
+
+ for (uint32_t index = 0; index < size; index++){
+ current_bucket_offset = next_bucket_offset;
+ next_bucket_offset = _get_next_offset(m, data, index, size);
+
+ DEBUG_ASSERT(next_bucket_offset <= current_bucket_offset + 1);
+ }
+
+}
+#else
+
+#define _os_map_verify(A)
+
+#endif
+
+#define _swap_if_needed IN_MAP(_,_swap_if_needed)
+
+static inline void
+_swap_if_needed(_os_map_t *m, _os_map_data_ref_t data, os_map_key_t *key,
+ void **val, uint32_t *bucket_offset, uint32_t i)
+{
+ if (*bucket_offset != 0) {
+ os_map_key_t loop_key = _get_key(data, i);
+
+ // Doesn't support inserting twice
+ DEBUG_ASSERT(!os_map_key_equals(loop_key, *key));
+
+ uint32_t loop_bucket_offset = _os_map_bucket_offset(m,
+ loop_key, i);
+ if (*bucket_offset > loop_bucket_offset) {
+ if (*bucket_offset > m->max_bucket_offset) {
+ assert(*bucket_offset <= UINT16_MAX);
+ DEBUG_ASSERT(*bucket_offset ==
+ m->max_bucket_offset + 1);
+ m->max_bucket_offset = *bucket_offset;
+ }
+ void *new_val = _get_val(data, i);
+ _set_key(data, i, *key);
+ _set_val(data, i, *val);
+ *key = loop_key;
+ *val = new_val;
+ *bucket_offset = loop_bucket_offset;
+ }
+ }
+}
+
+#define _os_map_insert_no_rehash IN_MAP(_,_insert_no_rehash)
+
+static void
+_os_map_insert_no_rehash(_os_map_t *m, os_map_key_t key, void *val)
+{
+ uint32_t size = m->size, loop_limit = m->size;
+ uint32_t i = os_map_hash(key) % size;
+ _os_map_data_ref_t data;
+ _get_data_ref(m, &data);
+
+ uint32_t bucket_offset = 0;
+ for (;;) {
+ DEBUG_ASSERT(bucket_offset ==
+ _os_map_bucket_offset(m, key, i));
+ assert(loop_limit-- != 0);
+ void *loop_val = _get_val(data, i);
+ if (loop_val == NULL) {
+ break;
+ }
+
+ _swap_if_needed(m, data, &key, &val, &bucket_offset, i);
+
+ bucket_offset++;
+ i = map_next(i, size);
+ }
+
+ DEBUG_ASSERT(_get_val(data, i) == NULL);
+
+ if (bucket_offset > m->max_bucket_offset) {
+ assert(bucket_offset <= UINT16_MAX);
+ DEBUG_ASSERT(bucket_offset == m->max_bucket_offset + 1);
+ m->max_bucket_offset = bucket_offset;
+ }
+ _set_key(data, i, key);
+ _set_val(data, i, val);
+ m->count++;
+}
+
+#define _os_map_rehash IN_MAP(_,_rehash)
+
+static void
+_os_map_rehash(_os_map_t *m, int direction)
+{
+ _os_map_verify(m);
+
+ uint32_t old_size = m->size;
+
+ _os_map_data_ref_t old_data;
+ _get_data_ref(m, &old_data);
+
+ // Grow shift is used instead of simply doubling the size each time in
+ // order to increase the expected utilization, thus decreasing overall
+ // memory usage, at the cost of more frequent rehashing.
+
+ if (direction > 0) {
+ m->size += (1 << m->grow_shift);
+ if (m->size ==
+ ((uint32_t)_MAP_GROW_SHIFT_RATE << m->grow_shift)) {
+ m->grow_shift++;
+ }
+ } else if (direction < 0) {
+ if (m->grow_shift > MAP_MINSHIFT) {
+ m->grow_shift--;
+ }
+ m->size = roundup(m->size / 2, (1 << m->grow_shift));
+ }
+
+ m->count = 0;
+ m->max_bucket_offset = 0;
+ m->data = _alloc_data(m->size);
+ assert(m->data);
+
+ for (uint32_t i = 0; i < old_size; i++) {
+ if (_get_val(old_data, i) == NULL) {
+ continue;
+ }
+
+ _os_map_insert_no_rehash(m, _get_key(old_data, i),
+ _get_val(old_data, i));
+ }
+ _free_data(&old_data);
+
+ _os_map_verify(m);
+}
+
+
+#define _os_map_find_helper_empty_key IN_MAP(_,_find_helper_empty_key)
+
+#define _os_map_find_helper IN_MAP(_,_find_helper)
+
+static inline void *
+_os_map_find_helper(_os_map_t *m, os_map_key_t key, uint32_t *i)
+{
+ if (m->count == 0) {
+ return NULL;
+ }
+
+
+ uint32_t size = m->size, loop_limit = m->size;
+ _os_map_data_ref_t data;
+ _get_data_ref(m, &data);
+
+ *i = _os_map_bucket(m, key);
+
+ uint32_t bucket_offset = 0;
+
+ for (;;) {
+ assert(loop_limit-- != 0);
+
+ if (bucket_offset > m->max_bucket_offset ||
+ _get_val(data, *i) == NULL) {
+ return NULL;
+ }
+
+ os_map_key_t loop_key = _get_key(data, *i);
+
+ if (os_map_key_equals(key, loop_key)) {
+ return _get_val(data, *i);
+ }
+ *i = map_next(*i, size);
+ bucket_offset++;
+ }
+}
+
+#define _os_map_remove_entry IN_MAP(_,_remove_entry)
+
+void
+_os_map_remove_entry(_os_map_t *m, uint32_t current_index)
+{
+ _os_map_data_ref_t data;
+ _get_data_ref(m, &data);
+
+ uint32_t size = m->size;
+
+ uint32_t next_index = map_next(current_index, size);
+ void *next_val = _get_val(data, next_index);
+ os_map_key_t next_key = _get_key(data, next_index);
+ while(next_val != NULL &&
+ _os_map_bucket(m, next_key) != next_index) {
+ _set_key(data, current_index, next_key);
+ _set_val(data, current_index, next_val);
+
+ DEBUG_ASSERT(_os_map_bucket_offset(m,
+ next_key, current_index) <
+ _os_map_bucket_offset(m, next_key,
+ next_index));
+
+ current_index = next_index;
+ next_index = map_next(current_index, size);
+ next_val = _get_val(data, next_index);
+ next_key = _get_key(data, next_index);
+ }
+
+ _set_val(data, current_index, NULL);
+ m->count--;
+
+ if ((m->size >= MAP_MINSIZE * 2) &&
+ (m->count < m->size / _MAP_MIN_FILL_DENOM)) {
+ // if the map density drops below 12%, shrink it
+ _os_map_rehash(m, -1);
+ }
+}
+
+// =========== Implementation ===========
+
+
+#define os_map_init IN_MAP(,_init)
+
+void
+os_map_init(opaque_os_map_t *m_raw, os_map_config_t *config,
+ __unused int struct_version)
+{
+ static_assert(sizeof(opaque_os_map_t) == sizeof(_os_map_t),
+ "Opaque string map incorrect size");
+ _os_map_t *m = (_os_map_t *)m_raw;
+
+ if (config) {
+ m->size = MAX(config->initial_size, MAP_MINSIZE);
+ } else {
+ m->size = MAP_MINSIZE;
+ }
+
+ m->count = 0;
+ m->max_bucket_offset = 0;
+ m->data = _alloc_data(m->size);
+ assert(m->data != NULL);
+ m->grow_shift = MAP_MINSHIFT;
+ DEBUG_ASSERT_MAP_INVARIANTS(m);
+}
+
+
+#define os_map_destroy IN_MAP(,_destroy)
+
+void
+os_map_destroy(opaque_os_map_t *m_raw)
+{
+ _os_map_t *m = (_os_map_t *)m_raw;
+ free(m->data);
+ m->data = NULL;
+ m->size = 0;
+}
+
+#define os_map_insert IN_MAP(,_insert)
+
+void
+os_map_insert(opaque_os_map_t *m_raw, os_map_key_t key, void *val)
+{
+ _os_map_t *m = (_os_map_str_t *)m_raw;
+
+ assert(val != NULL);
+
+ if (m->count >= _MAP_MAX_FILL_NUMER * m->size /
+ _MAP_MAX_FILL_DENOM) {
+ _os_map_rehash(m, 1);
+ }
+
+ _os_map_insert_no_rehash(m, key, val);
+
+ DEBUG_ASSERT_MAP_INVARIANTS(m);
+}
+
+
+#define os_map_find IN_MAP(,_find)
+
+void *
+os_map_find(opaque_os_map_t *m_raw, os_map_key_t key)
+{
+ _os_map_t *m = (_os_map_t *)m_raw;
+ uint32_t i;
+ return _os_map_find_helper(m, key, &i);
+}
+
+
+#define os_map_delete IN_MAP(,_delete)
+
+void *
+os_map_delete(opaque_os_map_t *m_raw, os_map_key_t key)
+{
+ _os_map_t *m = (_os_map_t *)m_raw;
+ uint32_t i;
+
+ void *val = _os_map_find_helper(m, key, &i);
+ if (val == NULL) {
+ return NULL;
+ }
+
+ _os_map_remove_entry(m, i);
+
+ return val;
+}
+
+#define os_map_payload_handler_t IN_MAP(,_payload_handler_t)
+typedef bool (^os_map_payload_handler_t) (os_map_key_t, void *);
+
+#define os_map_clear IN_MAP(,_clear)
+
+void
+os_map_clear(opaque_os_map_t *m_raw,
+ OS_NOESCAPE os_map_payload_handler_t handler)
+{
+ _os_map_t *m = (_os_map_t *)m_raw;
+
+ _os_map_data_ref_t oldData;
+ _get_data_ref(m, &oldData);
+ uint32_t oldSize = m->size;
+
+ m->count = 0;
+ m->max_bucket_offset = 0;
+ m->size = MAP_MINSIZE;
+ m->data = _alloc_data(m->size);
+ m->grow_shift = MAP_MINSHIFT;
+ DEBUG_ASSERT_MAP_INVARIANTS(m);
+
+ if (handler != NULL) {
+ for (uint32_t i = 0; i < oldSize; i++) {
+ void *val = _get_val(oldData, i);
+
+ if (val != NULL) {
+ handler(_get_key(oldData, i), val);
+ }
+ }
+ }
+
+ _free_data(&oldData);
+}
+
+
+#define os_map_count IN_MAP(,_count)
+
+size_t
+os_map_count(opaque_os_map_t *m_raw)
+{
+ _os_map_t *m = (_os_map_t *)m_raw;
+ return m->count;
+}
+
+
+#define os_map_foreach IN_MAP(,_foreach)
+
+void
+os_map_foreach(opaque_os_map_t *m_raw,
+ OS_NOESCAPE os_map_payload_handler_t handler)
+{
+ _os_map_t *m = (_os_map_t *)m_raw;
+ _os_map_data_ref_t data;
+ _get_data_ref(m, &data);
+
+ for (uint32_t i = 0; i < m->size; i++) {
+ void *val = _get_val(data, i);
+
+ if (val != NULL) {
+ if (!handler(_get_key(data, i), val)) break;
+ }
+ }
+}
+
+#ifdef MAP_SUPPORTS_ENTRY
+
+#define os_map_entry IN_MAP(,_entry)
+
+os_map_key_t
+os_map_entry(opaque_os_map_t *m_raw, os_map_key_t key)
+{
+ _os_map_t *m = (_os_map_t *)m_raw;
+ _os_map_data_ref_t data;
+ _get_data_ref(m, &data);
+
+ uint32_t i;
+ if (_os_map_find_helper(m, key, &i) == NULL) {
+ return (os_map_key_t)NULL;
+ }
+ return _get_key(data, i);
+}
+
+#endif
+
--- /dev/null
+/*
+* Copyright (c) 2019 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@
+*/
+
+#ifndef collections_utilities_h
+#define collections_utilities_h
+
+#ifndef roundup
+#define roundup(x, y) ((((x) % (y)) == 0) ? \
+ (x) : ((x) + ((y) - ((x) % (y)))))
+#endif /* roundup */
+
+/* Macros for min/max. */
+#ifndef MIN
+#define MIN(a, b) (((a)<(b))?(a):(b))
+#endif /* MIN */
+#ifndef MAX
+#define MAX(a, b) (((a)>(b))?(a):(b))
+#endif /* MAX */
+
+#define MAP_MINSHIFT 5
+#define MAP_MINSIZE (1 << MAP_MINSHIFT)
+
+#ifdef DEBUG
+
+#define DEBUG_ASSERT(X) assert(X)
+
+#define DEBUG_ASSERT_MAP_INVARIANTS(m) \
+ assert(m->data); \
+ assert(m->size >= MAP_MINSIZE); \
+ assert(m->count < m->size)
+
+#else
+
+#define DEBUG_ASSERT(X)
+
+#define DEBUG_ASSERT_MAP_INVARIANTS(map)
+
+
+#endif
+
+#endif /* collections_utilities_h */
--- /dev/null
+/* package up error # */
+"error %1$d" = "error %1$d";
+"error %1$#x" = "error %1$#x";
+/* errno error 0 */
+"Undefined error: 0" = "Undefined error: 0";
+
+/* errno error 1 */
+"Operation not permitted" = "Operation not permitted";
+
+/* errno error 2 */
+"No such file or directory" = "No such file or directory";
+
+/* errno error 3 */
+"No such process" = "No such process";
+
+/* errno error 4 */
+"Interrupted system call" = "Interrupted system call";
+
+/* errno error 5 */
+"Input/output error" = "Input/output error";
+
+/* errno error 6 */
+"Device not configured" = "Device not configured";
+
+/* errno error 7 */
+"Argument list too long" = "Argument list too long";
+
+/* errno error 8 */
+"Exec format error" = "Exec format error";
+
+/* errno error 9 */
+"Bad file descriptor" = "Bad file descriptor";
+
+/* errno error 10 */
+"No child processes" = "No child processes";
+
+/* errno error 11 */
+"Resource deadlock avoided" = "Resource deadlock avoided";
+
+/* errno error 12 */
+"Cannot allocate memory" = "Cannot allocate memory";
+
+/* errno error 13 */
+"Permission denied" = "Permission denied";
+
+/* errno error 14 */
+"Bad address" = "Bad address";
+
+/* errno error 15 */
+"Block device required" = "Block device required";
+
+/* errno error 16 */
+"Resource busy" = "Resource busy";
+
+/* errno error 17 */
+"File exists" = "File exists";
+
+/* errno error 18 */
+"Cross-device link" = "Cross-device link";
+
+/* errno error 19 */
+"Operation not supported by device" = "Operation not supported by device";
+
+/* errno error 20 */
+"Not a directory" = "Not a directory";
+
+/* errno error 21 */
+"Is a directory" = "Is a directory";
+
+/* errno error 22 */
+"Invalid argument" = "Invalid argument";
+
+/* errno error 23 */
+"Too many open files in system" = "Too many open files in system";
+
+/* errno error 24 */
+"Too many open files" = "Too many open files";
+
+/* errno error 25 */
+"Inappropriate ioctl for device" = "Inappropriate ioctl for device";
+
+/* errno error 26 */
+"Text file busy" = "Text file busy";
+
+/* errno error 27 */
+"File too large" = "File too large";
+
+/* errno error 28 */
+"No space left on device" = "No space left on device";
+
+/* errno error 29 */
+"Illegal seek" = "Illegal seek";
+
+/* errno error 30 */
+"Read-only file system" = "Read-only file system";
+
+/* errno error 31 */
+"Too many links" = "Too many links";
+
+/* errno error 32 */
+"Broken pipe" = "Broken pipe";
+
+/* errno error 33 */
+"Numerical argument out of domain" = "Numerical argument out of domain";
+
+/* errno error 34 */
+"Result too large" = "Result too large";
+
+/* errno error 35 */
+"Resource temporarily unavailable" = "Resource temporarily unavailable";
+
+/* errno error 36 */
+"Operation now in progress" = "Operation now in progress";
+
+/* errno error 37 */
+"Operation already in progress" = "Operation already in progress";
+
+/* errno error 38 */
+"Socket operation on non-socket" = "Socket operation on non-socket";
+
+/* errno error 39 */
+"Destination address required" = "Destination address required";
+
+/* errno error 40 */
+"Message too long" = "Message too long";
+
+/* errno error 41 */
+"Protocol wrong type for socket" = "Protocol wrong type for socket";
+
+/* errno error 42 */
+"Protocol not available" = "Protocol not available";
+
+/* errno error 43 */
+"Protocol not supported" = "Protocol not supported";
+
+/* errno error 44 */
+"Socket type not supported" = "Socket type not supported";
+
+/* errno error 45 */
+"Operation not supported" = "Operation not supported";
+
+/* errno error 46 */
+"Protocol family not supported" = "Protocol family not supported";
+
+/* errno error 47 */
+"Address family not supported by protocol family" = "Address family not supported by protocol family";
+
+/* errno error 48 */
+"Address already in use" = "Address already in use";
+
+/* errno error 49 */
+"Can't assign requested address" = "Can't assign requested address";
+
+/* errno error 50 */
+"Network is down" = "Network is down";
+
+/* errno error 51 */
+"Network is unreachable" = "Network is unreachable";
+
+/* errno error 52 */
+"Network dropped connection on reset" = "Network dropped connection on reset";
+
+/* errno error 53 */
+"Software caused connection abort" = "Software caused connection abort";
+
+/* errno error 54 */
+"Connection reset by peer" = "Connection reset by peer";
+
+/* errno error 55 */
+"No buffer space available" = "No buffer space available";
+
+/* errno error 56 */
+"Socket is already connected" = "Socket is already connected";
+
+/* errno error 57 */
+"Socket is not connected" = "Socket is not connected";
+
+/* errno error 58 */
+"Can't send after socket shutdown" = "Can't send after socket shutdown";
+
+/* errno error 59 */
+"Too many references: can't splice" = "Too many references: can't splice";
+
+/* errno error 60 */
+"Operation timed out" = "Operation timed out";
+
+/* errno error 61 */
+"Connection refused" = "Connection refused";
+
+/* errno error 62 */
+"Too many levels of symbolic links" = "Too many levels of symbolic links";
+
+/* errno error 63 */
+"File name too long" = "File name too long";
+
+/* errno error 64 */
+"Host is down" = "Host is down";
+
+/* errno error 65 */
+"No route to host" = "No route to host";
+
+/* errno error 66 */
+"Directory not empty" = "Directory not empty";
+
+/* errno error 67 */
+"Too many processes" = "Too many processes";
+
+/* errno error 68 */
+"Too many users" = "Too many users";
+
+/* errno error 69 */
+"Disc quota exceeded" = "Disc quota exceeded";
+
+/* errno error 70 */
+"Stale NFS file handle" = "Stale NFS file handle";
+
+/* errno error 71 */
+"Too many levels of remote in path" = "Too many levels of remote in path";
+
+/* errno error 72 */
+"RPC struct is bad" = "RPC struct is bad";
+
+/* errno error 73 */
+"RPC version wrong" = "RPC version wrong";
+
+/* errno error 74 */
+"RPC prog. not avail" = "RPC prog. not avail";
+
+/* errno error 75 */
+"Program version wrong" = "Program version wrong";
+
+/* errno error 76 */
+"Bad procedure for program" = "Bad procedure for program";
+
+/* errno error 77 */
+"No locks available" = "No locks available";
+
+/* errno error 78 */
+"Function not implemented" = "Function not implemented";
+
+/* errno error 79 */
+"Inappropriate file type or format" = "Inappropriate file type or format";
+
+/* errno error 80 */
+"Authentication error" = "Authentication error";
+
+/* errno error 81 */
+"Need authenticator" = "Need authenticator";
+
+/* errno error 82 */
+"Device power is off" = "Device power is off";
+
+/* errno error 83 */
+"Device error" = "Device error";
+
+/* errno error 84 */
+"Value too large to be stored in data type" = "Value too large to be stored in data type";
+
+/* errno error 85 */
+"Bad executable (or shared library)" = "Bad executable (or shared library)";
+
+/* errno error 86 */
+"Bad CPU type in executable" = "Bad CPU type in executable";
+
+/* errno error 87 */
+"Shared library version mismatch" = "Shared library version mismatch";
+
+/* errno error 88 */
+"Malformed Mach-o file" = "Malformed Mach-o file";
+
+/* errno error 89 */
+"Operation canceled" = "Operation canceled";
+
+/* errno error 90 */
+"Identifier removed" = "Identifier removed";
+
+/* errno error 91 */
+"No message of desired type" = "No message of desired type";
+
+/* errno error 92 */
+"Illegal byte sequence" = "Illegal byte sequence";
+
+/* errno error 93 */
+"Attribute not found" = "Attribute not found";
+
+/* errno error 94 */
+"Bad message" = "Bad message";
+
+/* errno error 95 */
+"EMULTIHOP (Reserved)" = "EMULTIHOP (Reserved)";
+
+/* errno error 96 */
+"No message available on STREAM" = "No message available on STREAM";
+
+/* errno error 97 */
+"ENOLINK (Reserved)" = "ENOLINK (Reserved)";
+
+/* errno error 98 */
+"No STREAM resources" = "No STREAM resources";
+
+/* errno error 99 */
+"Not a STREAM" = "Not a STREAM";
+
+/* errno error 100 */
+"Protocol error" = "Protocol error";
+
+/* errno error 101 */
+"STREAM ioctl timeout" = "STREAM ioctl timeout";
+
+/* errno error 102 */
+"Operation not supported on socket" = "Operation not supported on socket";
+
+/* errno error 103 */
+"Policy not found" = "Policy not found";
+
+/* errno error 104 */
+"State not recoverable" = "State not recoverable";
+
+/* errno error 105 */
+"Previous owner died" = "Previous owner died";
+
+/* errno error 106 */
+"Interface output queue is full" = "Interface output queue is full";
--- /dev/null
+/*
+* Copyright (c) 2019 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 <fcntl.h>
+#include <stdbool.h>
+#include <string.h>
+#include <subsystem.h>
+#include <sys/errno.h>
+#include <sys/syslimits.h>
+#include <_simple.h>
+
+#define SUBSYSTEM_ROOT_PATH_KEY "subsystem_root_path"
+
+void _subsystem_init(const char *apple[]);
+
+static char * subsystem_root_path = NULL;
+static size_t subsystem_root_path_len = 0;
+
+/*
+ * Takes the apple array, and initializes subsystem
+ * support in Libc.
+ */
+void
+_subsystem_init(const char **apple)
+{
+ char * subsystem_root_path_string = _simple_getenv(apple, SUBSYSTEM_ROOT_PATH_KEY);
+ if (subsystem_root_path_string) {
+ subsystem_root_path = subsystem_root_path_string;
+ subsystem_root_path_len = strnlen(subsystem_root_path, PATH_MAX);
+ }
+}
+
+/*
+ * Takes a buffer, a subsystem path, and a file path, and constructs the
+ * subsystem path for the given file path. Assumes that the subsystem root
+ * path will be "/" terminated.
+ */
+static bool
+construct_subsystem_path(char * buf, size_t buf_size, const char * subsystem_root_path, const char * file_path)
+{
+ size_t return_a = strlcpy(buf, subsystem_root_path, buf_size);
+ size_t return_b = strlcat(buf, file_path, buf_size);
+
+ if ((return_a >= buf_size) || (return_b >= buf_size)) {
+ return false;
+ }
+
+ return true;
+}
+
+int
+open_with_subsystem(const char * path, int oflag)
+{
+ /* Don't support file creation. */
+ if (oflag & O_CREAT){
+ errno = EINVAL;
+ return -1;
+ }
+
+ int result;
+
+ result = open(path, oflag);
+
+ if ((result < 0) && (errno == ENOENT) && (subsystem_root_path)) {
+ /*
+ * If the file doesn't exist relative to root, search
+ * for it relative to the subsystem root.
+ */
+ char subsystem_path[PATH_MAX];
+
+ if (construct_subsystem_path(subsystem_path, sizeof(subsystem_path), subsystem_root_path, path)) {
+ result = open(subsystem_path, oflag);
+ } else {
+ errno = ENAMETOOLONG;
+ }
+ }
+
+ return result;
+}
+
+int
+stat_with_subsystem(const char *restrict path, struct stat *restrict buf)
+{
+ int result;
+
+ result = stat(path, buf);
+
+ if ((result < 0) && (errno == ENOENT) && (subsystem_root_path)) {
+ /*
+ * If the file doesn't exist relative to root, search
+ * for it relative to the subsystem root.
+ */
+ char subsystem_path[PATH_MAX];
+
+ if (construct_subsystem_path(subsystem_path, sizeof(subsystem_path), subsystem_root_path, path)) {
+ result = stat(subsystem_path, buf);
+ } else {
+ errno = ENAMETOOLONG;
+ }
+ }
+
+ return result;
+}
+
--- /dev/null
+/*
+* Copyright (c) 2019 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@
+*/
+
+#ifndef __SUBSYSTEM_H__
+#define __SUBSYSTEM_H__
+
+#include <sys/stat.h>
+
+__BEGIN_DECLS
+/*
+ * Returns an fd for the given path, relative to root or to
+ * the subsystem root for the process. Behaves exactly like
+ * open in every way, except O_CREAT is forbidden.
+ *
+ * Returns a file descriptor on success, or -1 on failure.
+ * errno is set exactly as open would have set it, except
+ * that O_CREAT will result in EINVAL.
+ */
+int open_with_subsystem(const char * path, int oflag);
+
+/*
+ * Invokes stat for the given path, relative to root or to
+ * the subsystem root for the process. Behaves exactly like
+ * stat in every way.
+ *
+ * Returns 0 on success, or -1 on failure. On failure, errno
+ * is set exactly as stat would have set it.
+ */
+int stat_with_subsystem(const char *__restrict path, struct stat *__restrict buf);
+__END_DECLS
+
+#endif /* __SUBSYSTEM_H__ */
XXX this is a *huge* kludge to pass the SuSv3 tests,
I don't think of it as cheating because they are
- looking in the wrong place (/realdev/console) to do
+ looking in the wrong place (/var/log/console) to do
their testing, but they can't look in the "right"
place for various reasons */
char *cpath = "/dev/console";
struct stat sb;
- int rc = stat("/realdev/console", &sb);
+ int rc = stat("/var/log/console", &sb);
if (rc == 0 && (sb.st_mode & S_IFDIR)) {
- cpath = "/realdev/console";
+ cpath = "/var/log/console";
}
/* XXX thus ends the kludge - changes after
this point may be safely integrated */
#include <unistd.h>
#include "un-namespace.h"
+#if TARGET_OS_OSX && !TARGET_OS_SIMULATOR
+#include <sys/attr.h> /* for FSOPT_NOFOLLOW */
+#include <apfs/apfs_fsctl.h>
+#endif
+
#define ISDOT(dp) \
(dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
(dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
+/*
+ * Check if the given directory is a firmlink.
+ * Return 1 if it is firmlink otherwise return 0.
+ */
+static inline int
+__check_for_firmlink(char *dir_path)
+{
+#if TARGET_OS_OSX && !TARGET_OS_SIMULATOR
+ apfs_firmlink_control_t afc;
+ int is_firmlink;
+ int err;
+
+ afc.cmd = FIRMLINK_GET;
+ afc.val = 0;
+
+ err = fsctl(dir_path, APFSIOC_FIRMLINK_CTL, (void *)&afc, FSOPT_NOFOLLOW);
+ if (err == 0) {
+ is_firmlink = afc.val ? 1 : 0;
+ } else {
+ /*
+ * On error, we assume it is a firmlink. This could be a false positive
+ * and we will end up incurring a lstat() cost but it will give us some
+ * chance to build the path successfully.
+ */
+ is_firmlink = 1;
+ }
+
+ return is_firmlink;
+#else
+ return 0;
+#endif
+}
+
/*
* If __getcwd() ever becomes a syscall, we can remove this workaround.
* The problem here is that fcntl() assumes a buffer of size MAXPATHLEN,
for (;;) {
if (!(dp = readdir(dir)))
goto notfound;
- if (dp->d_fileno == ino)
+ if (dp->d_fileno == ino) {
break;
+ } else if (!ISDOT(dp) && dp->d_type == DT_DIR) {
+ /*
+ * The 'd_fileno' for firmlink directory would be different
+ * than the 'st_ino' returned by stat(). We have to do an
+ * extra lstat() on firmlink directory to determine if the
+ * 'st_ino' matches with what we are looking for.
+ */
+ bcopy(dp->d_name, bup, dp->d_namlen + 1);
+
+ if (__check_for_firmlink(up) == 0)
+ continue;
+
+ if (lstat(up, &s)) {
+ if (!save_errno)
+ save_errno = errno;
+ errno = 0;
+ continue;
+ }
+ if (s.st_dev == dev && s.st_ino == ino)
+ break;
+ }
}
} else
for (;;) {
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/lib/libc/gen/getmntinfo.c,v 1.5 2007/01/09 00:27:54 imp Exp $");
+#if !__DARWIN_ONLY_64_BIT_INO_T
+
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>
*mntbufp = mntbuf;
return (mntsize);
}
+#endif
.Sh NAME
.Nm psignal ,
.Nm strsignal ,
+.Nm strsignal_r ,
.Nm sys_siglist ,
.Nm sys_signame
.Nd system signal messages
.In string.h
.Ft "char *"
.Fn strsignal "int sig"
+.Ft "int"
+.Fo strsignal_r
+.Fa "int sig"
+.Fa "char *strsignalbuf"
+.Fa "size_t buflen"
+.Fc
.Sh DESCRIPTION
The
-.Fn psignal
+.Fn psignal ,
+.Fn strsignal ,
and
-.Fn strsignal
+.Fn strsignal_r
functions locate the descriptive message
string for a signal number.
.Pp
and returns a pointer to the corresponding message string.
.Pp
The
+.Fn strsignal_r
+function renders the same result into
+.Fa strsignalbuf
+for a maximum of
+.Fa buflen
+characters and returns 0 upon success.
+.Pp
+The
.Fn psignal
function accepts a signal number argument
.Fa sig
a pointer to the desired message or a NULL value indicating an error. This
string is not to be freed by the caller. Beginning with Mac OSX 10.7, this
string is unique to each thread.
+.Pp
+.Fn strsignal_r
+0 if the message string is successfully copied in its entirety to
+.Fa strsignalbuf .
+.Pp
.Sh ERRORS
.Fn strsignal
will fail and no additional memory will be allocated if
.It Bq Er ENOMEM
There was insufficient memory to allocate storage space for the return value in the running thread.
.El
+.Pp
+.Fn strsignal_r
+will return an error (but not fail) if one or more condition is met:
+.Bl -tag -width Er
+.It Bq Er ERANGE
+.Fa buflen
+is not long enough to fit the length of the message.
+.Fa strsignalbuf
+will contain the message string that has been truncated and
+NUL terminated to fit the length specified by
+.Fa buflen .
+.El
+.Bl -tag -width Er
+.It Bq Er EINVAL
+.Fa sig
+<= 0 or >= NSIG.
+.El
.Sh SEE ALSO
.Xr sigaction 2 ,
.Xr perror 3 ,
case _SC_STREAM_MAX: /* assume fds run out before memory does */
if (getrlimit(RLIMIT_NOFILE, &rl) != 0)
return (-1);
- if (rl.rlim_cur == RLIM_INFINITY)
+#if __LP64__
+ /*
+ * In 64 bit world, sysconf is able to correctly represent
+ * rlim_t values (8 bytes).
+ */
+ if (rl.rlim_cur > RLIM_INFINITY)
return (-1);
if (rl.rlim_cur > LONG_MAX) {
errno = EOVERFLOW;
return (-1);
}
- return ((long)rl.rlim_cur);
+ lvalue = rl.rlim_cur;
+#else
+ /*
+ * In 32 bit world (watches), sysconf falls back to the
+ * old behavior: use (int) OPEN_MAX as max limit. Ideally
+ * we would use maxfilesperproc as max limit, which is a
+ * system value adjusted by the kernel based on available
+ * RAM size. This value defaults to OPEN_MAX for systems
+ * with less than 8G of RAM. So we use OPEN_MAX (defined
+ * in sys/syslimits.h) as max limit here in case
+ * applications with strict sandbox rules prevent libc
+ * from reading maxfilesperproc via sysctl.
+ */
+ if (rl.rlim_cur > OPEN_MAX)
+ lvalue = OPEN_MAX;
+ else
+ lvalue = (long)rl.rlim_cur;
+#endif
+ return lvalue;
case _SC_JOB_CONTROL:
return (_POSIX_JOB_CONTROL);
case _SC_SAVED_IDS:
#include <unistd.h>
#include <string.h>
-extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
- void *newp, size_t newlen);
+#include "sysctl_internal.h"
+
int
sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
*oldlenp = 2;
return 0;
}
- return (__sysctl(name, namelen, oldp, oldlenp, newp, newlen));
+
+
+ int error = __sysctl(name, namelen, oldp, oldlenp, newp, newlen);
+ if (error < 0) {
+ return error;
+ }
+
+
+ return error;
}
if (newp != NULL) {
--- /dev/null
+/*
+* Copyright (c) 2020 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@
+*/
+
+#ifndef __SYSCTL_INTERNAL_H__
+#define __SYSCTL_INTERNAL_H__
+
+
+extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
+ void *newp, size_t newlen);
+
+extern int
+__sysctlbyname(const char *name, size_t namelen, void *oldp, size_t *oldlenp,
+ void *newp, size_t newlen);
+
+#endif /* __SYSCTL_INTERNAL_H__ */
#include <sys/errno.h>
#include <TargetConditionals.h>
-extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
- void *newp, size_t newlen);
-extern int
-__sysctlbyname(const char *name, size_t namelen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen);
+#include "sysctl_internal.h"
+
int
sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
size_t newlen)
{
- int name2oid_oid[2];
- int real_oid[CTL_MAXNAME+2];
int error;
- size_t oidlen;
-#if !TARGET_IPHONE_SIMULATOR
- /* Try primary system call first, fall back if not supported */
+
error = __sysctlbyname(name, strlen(name), oldp, oldlenp, newp, newlen);
- if ((error == 0) || (errno != ENOSYS))
- return error;
-#endif /* !TARGET_IPHONE_SIMULATOR */
-
- name2oid_oid[0] = 0; /* This is magic & undocumented! */
- name2oid_oid[1] = 3;
-
- oidlen = sizeof(real_oid);
- error = __sysctl(name2oid_oid, 2, real_oid, &oidlen, (void *)name,
- strlen(name));
- if (error < 0)
+ if (error < 0) {
return error;
- oidlen /= sizeof (int);
- error = __sysctl(real_oid, oidlen, oldp, oldlenp, newp, newlen);
- return (error);
+ }
+
+
+ return error;
}
#include <sys/sysctl.h>
#include <string.h>
-extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
- void *newp, size_t newlen);
+#include "sysctl_internal.h"
/*
* This function uses a presently undocumented interface to the kernel
-/*
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
* Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* SUCH DAMAGE.
*/
+#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)ualarm.c 8.1 (Berkeley) 6/4/93";
+__SCCSID("@(#)ualarm.c 8.1 (Berkeley) 6/4/93");
+__FBSDID("$FreeBSD$");
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/gen/ualarm.c,v 1.5 2007/01/09 00:27:56 imp Exp $");
#include <sys/time.h>
#include <unistd.h>
* every ``reload'' microseconds after the first signal.
*/
useconds_t
-ualarm(usecs, reload)
- useconds_t usecs;
- useconds_t reload;
+ualarm(useconds_t usecs, useconds_t reload)
{
struct itimerval new, old;
if (setitimer(ITIMER_REAL, &new, &old) == 0)
return (old.it_value.tv_sec * USPS + old.it_value.tv_usec);
- /* else */
- return (-1);
+ return (-1);
}
-.Dd June 30, 2010
+.Dd July 21, 2020
.Os Darwin
.Dt COMPAT 5
.Sh NAME
.Nd manipulate compatibility settings
.Sh SYNOPSIS
.Ev COMMAND_MODE=legacy|unix2003
+.br
+.Ev SYSTEM_VERSION_COMPAT=1
.Lp
.Fd #define _POSIX_C_SOURCE
.Fd #define _DARWIN_C_SOURCE
.Ev COMMAND_MODE
is case insensitive and if it is unset or set to something other than legacy
or unix2003 it behaves as if it were set to unix2003.
+.Pp
+Setting the environment variable
+.Ev SYSTEM_VERSION_COMPAT
+to 1 causes the system version to be reported as 10.16 when running on macOS 11 or later.
.Sh COMPILATION
Defining
.Dv _NONSTD_SOURCE
}
(void)close(p->fts_symfd);
} else if (!(p->fts_flags & FTS_DONTCHDIR) &&
- fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
+ fts_safe_changedir(sp, p, -1, "..")) {
SET(FTS_STOP);
sp->fts_cur = p;
return (NULL);
*/
if (descend && (type == BCHILD || !nitems) &&
(cur->fts_level == FTS_ROOTLEVEL ? FCHDIR(sp, sp->fts_rfd) :
- fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
+ fts_safe_changedir(sp, cur, -1, ".."))) {
cur->fts_info = FTS_ERR;
SET(FTS_STOP);
return (NULL);
}
#endif
+ if (fd != -1) {
+ // Going down
+ struct stat csb;
+ int cfd = open(".", O_RDONLY | O_CLOEXEC);
+ if (cfd < 0) {
+ ret = -1;
+ goto bail;
+ } else if (fstat(cfd, &csb)) {
+ oerrno = errno;
+ (void)close(cfd);
+ errno = oerrno;
+ ret = -1;
+ goto bail;
+ } else {
+ if (sb.st_dev != csb.st_dev) {
+ // Changed device, so we'll need to track the fd of the current
+ // directory
+ p->fts_symfd = cfd;
+ p->fts_flags |= FTS_CHDIRFD;
+ } else {
+ // Same device so assume open("..") will work
+ (void)close(cfd);
+ }
+ }
+ } else if (fd == -1 && strcmp(path, "..") == 0) {
+ // Going up
+ if (p->fts_flags & FTS_CHDIRFD) {
+ // If FTS_CHDIRFD is set, use the stashed fd to follow ".."
+ (void)close(newfd);
+ newfd = p->fts_symfd;
+ p->fts_symfd = 0;
+ p->fts_flags &= ~FTS_CHDIRFD;
+ }
+ }
+
ret = fchdir(newfd);
bail:
oerrno = errno;
/*
- * Copyright (c) 2000, 2002-2006, 2008-2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2002-2006, 2008-2010, 2012, 2020 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#ifndef _CTERMID_H_
#define _CTERMID_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
char *ctermid(char *);
+
+__END_DECLS
+
#endif
--- /dev/null
+// Module map for the non-stdint.h parts of _types/.
+//
+// Expected to be included by the top-level module.modulemap.
+//
+// See also: module.modulemap
+// See also: stdint.modulemap (excluded parts of _types/)
+
+module Darwin.POSIX._types {
+ export *
+ umbrella "_types"
+
+ // These headers are part of Darwin_C_stdint._types.
+ exclude header "_types/_intmax_t.h"
+ exclude header "_types/_uint16_t.h"
+ exclude header "_types/_uint32_t.h"
+ exclude header "_types/_uint64_t.h"
+ exclude header "_types/_uint8_t.h"
+ exclude header "_types/_uintmax_t.h"
+
+ // Export everything.
+ module * { export * }
+}
char *fts_accpath; /* access path */
char *fts_path; /* root path */
int fts_errno; /* errno for this node */
- int fts_symfd; /* fd for symlink */
+ int fts_symfd; /* fd for symlink or chdir */
unsigned short fts_pathlen; /* strlen(fts_path) */
unsigned short fts_namelen; /* strlen(fts_name) */
#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
#define FTS_ISW 0x04 /* this is a whiteout object */
+#define FTS_CHDIRFD 0x08 /* indicates the fts_symfd field was set for chdir */
unsigned short fts_flags; /* private flags for FTSENT structure */
#define FTS_AGAIN 1 /* read node again */
/* Define pressure levels usable by OSThermalPressureLevel */
typedef enum {
-#if TARGET_OS_OSX || TARGET_OS_IOSMAC
+#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
kOSThermalPressureLevelNominal = 0,
kOSThermalPressureLevelModerate,
kOSThermalPressureLevelHeavy,
__END_DECLS
/* List definitions after function declarations, or Reiser cpp gets upset. */
-#if defined(__i386__) || defined(__x86_64__)
-/* The left shift operator on intel is modulo 32 */
__header_always_inline int
__sigbits(int __signo)
{
return __signo > __DARWIN_NSIG ? 0 : (1 << (__signo - 1));
}
-#else /* !__i386__ && !__x86_64__ */
-#define __sigbits(signo) (1 << ((signo) - 1))
-#endif /* __i386__ || __x86_64__ */
#define sigaddset(set, signo) (*(set) |= __sigbits(signo), 0)
#define sigdelset(set, signo) (*(set) &= ~__sigbits(signo), 0)
--- /dev/null
+// Module map for stdint.h.
+//
+// Expected to be included by the top-level module.modulemap.
+//
+// See also: module.modulemap
+// See also: _types.modulemap (reset of _types/)
+
+// This is a module for the version of stdint.h provided by Libc. It is a
+// standalone module to allow Clang's builtins and libc++ to interpose and then
+// call #include_next.
+module Darwin_C_stdint [system] [extern_c] [no_undeclared_includes] {
+ export *
+
+ module stdint {
+ export *
+ header "stdint.h"
+ }
+
+ extern module _pthread_types "sys_pthread_types.modulemap"
+ extern module _sys_types "sys__types.modulemap"
+ extern module _sys_cdefs "sys_cdefs.modulemap"
+ extern module _machine_types "machine_types.modulemap"
+
+ module _types {
+ export *
+
+ module _intmax_t {
+ export *
+ header "_types/_intmax_t.h"
+ }
+ module _uint16_t {
+ export *
+ header "_types/_uint16_t.h"
+ }
+ module _uint32_t {
+ export *
+ header "_types/_uint32_t.h"
+ }
+ module _uint64_t {
+ export *
+ header "_types/_uint64_t.h"
+ }
+ module _uint8_t {
+ export *
+ header "_types/_uint8_t.h"
+ }
+ module _uintmax_t {
+ export *
+ header "_types/_uintmax_t.h"
+ }
+ }
+}
/* Additional functionality provided by:
* POSIX.2-1992 C Language Binding Option
*/
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
#define __swift_unavailable_on(osx_msg, ios_msg) __swift_unavailable(ios_msg)
#else
#define __swift_unavailable_on(osx_msg, ios_msg) __swift_unavailable(osx_msg)
#ifndef LIBC_ALIAS_SYSTEM
//End-Libc
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
#define __swift_unavailable_on(osx_msg, ios_msg) __swift_unavailable(ios_msg)
#else
#define __swift_unavailable_on(osx_msg, ios_msg) __swift_unavailable(osx_msg)
void sranddev(void);
void srandomdev(void);
void *reallocf(void *__ptr, size_t __size) __alloc_size(2);
+long long
+ strtonum(const char *__numstr, long long __minval, long long __maxval, const char **__errstrp)
+ __API_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0));
#endif /* UNIFDEF_DRIVERKIT */
#if !__DARWIN_NO_LONG_LONG
long long
__OSX_AVAILABLE(10.12.1) __IOS_AVAILABLE(10.1)
__TVOS_AVAILABLE(10.0.1) __WATCHOS_AVAILABLE(3.1)
int timingsafe_bcmp(const void *__b1, const void *__b2, size_t __len);
+
+__OSX_AVAILABLE(10.16) __IOS_AVAILABLE(14.0)
+__TVOS_AVAILABLE(14.0) __WATCHOS_AVAILABLE(7.0)
+int strsignal_r(int __sig, char *__strsignalbuf, size_t __buflen);
__END_DECLS
/* Some functions historically defined in string.h were placed in strings.h
#include <Availability.h>
#include <sys/kauth.h>
+#include <sys/_types/_ssize_t.h>
#define __DARWIN_ACL_READ_DATA (1<<1)
#define __DARWIN_ACL_LIST_DIRECTORY __DARWIN_ACL_READ_DATA
#include <sys/cdefs.h>
#include <stdint.h>
+#include <stddef.h> /* wchar_t */
#include <_xlocale.h>
__BEGIN_DECLS
#include <_stdio.h>
#include <_xlocale.h>
#include <sys/_types/_mbstate_t.h>
+#include <sys/_types/_wint_t.h>
+#include <stddef.h> /* wchar_t */
/* Initially added in Issue 4 */
__BEGIN_DECLS
#pragma mark Definitions
#define CTL_OUTPUT_WIDTH (80)
-#define CTL_OUTPUT_OPTARG_PAD (28)
-#define CTL_OUTPUT_LIST_PAD (4)
+#define CTL_OUTPUT_OPTARG_INDENT (32)
+#define CTL_OUTPUT_OPTARG_OVERFLOW (CTL_OUTPUT_OPTARG_INDENT - 4)
#define SUBCOMMAND_LINKER_SET "__subcommands"
#define OS_SUBCOMMAND_OPTIONS_FOREACH(_osco_i, _osc, _which, _i) \
static void _os_subcommand_print_help_line(
const os_subcommand_t *osc,
FILE *f);
+static void _print_subcommand_list(
+ const os_subcommand_t *osc,
+ FILE *f);
#pragma mark Module Globals
static const os_subcommand_t __help_cmd;
static const os_subcommand_t *_main_cmd = &__main_cmd;
static const os_subcommand_t *_internal_main_cmd = &__main_cmd;
+static struct ttysize __ttys = {
+ .ts_lines = 24,
+ .ts_cols = CTL_OUTPUT_WIDTH,
+};
+
+static const struct ttysize *_ttys = &__ttys;
+
+#pragma mark Module Private
+static void
+_init_column_count(void)
+{
+ const char *columns_env = NULL;
+ char *end = NULL;
+ struct ttysize ttys = {
+ .ts_lines = 24,
+ .ts_cols = CTL_OUTPUT_WIDTH,
+ };
+ int ret = -1;
+
+ columns_env = getenv("COLUMNS");
+ if (columns_env) {
+ unsigned short cols = -1;
+
+ cols = strtoul(columns_env, &end, 0);
+ if (end != columns_env && end[0] != 0) {
+ ttys.ts_lines = cols;
+ }
+ } else {
+ ret = ioctl(0, TIOCGSIZE, &ttys);
+ if (ret) {
+ ttys.ts_lines = 24;
+ ttys.ts_cols = CTL_OUTPUT_WIDTH;
+ }
+ }
+
+ __ttys = ttys;
+}
+
+static void
+_stoupper(char *str)
+{
+ size_t i = 0;
+ size_t len = strlen(str);
+
+ for (i = 0; i < len; i++) {
+ char *cp = &str[i];
+ *cp = ___toupper(*cp);
+ }
+}
+
#pragma mark Main Subcommand
static int _main_invoke(const os_subcommand_t *osc,
int argc,
.osco_version = OS_SUBCOMMAND_OPTION_VERSION,
.osco_flags = 0,
.osco_option = NULL,
- .osco_argument_usage = "subcommand",
+ .osco_argument_usage = "SUBCOMMAND",
.osco_argument_human = "The subcommand to query for help",
},
OS_SUBCOMMAND_OPTION_TERMINATOR,
cmdname = argv[1];
}
- if (cmdname) {
- // Print usage information for the requested subcommand.
- target = _os_subcommand_find(argv[1]);
- if (!target) {
- os_subcommand_fprintf(osc, stderr, "unrecognized subcommand: %s",
- argv[1]);
- xit = EX_USAGE;
- } else {
- xit = 0;
- }
- } else {
- // Print general, top-level usage followed by a list of subcommands.
+ // Print usage information for the requested subcommand.
+ target = _os_subcommand_find(cmdname);
+ if (!target) {
+ // If it's a bogus subcommand, just print top-level usage.
+ fprintf(stderr, "unrecognized subcommand: %s\n", cmdname);
target = _main_cmd;
+ xit = EX_UNAVAILABLE;
+ } else {
xit = 0;
}
_os_subcommand_print_usage(target, f);
if (target == _main_cmd) {
- const os_subcommand_t **oscip = NULL;
- const os_subcommand_t *osci = NULL;
- bool header_printed = false;
-
- LINKER_SET_FOREACH(oscip, const os_subcommand_t **,
- SUBCOMMAND_LINKER_SET) {
- osci = *oscip;
-
- _print_header(f, "subcommands", &header_printed);
- _os_subcommand_print_help_line(osci, f);
- }
-
- // Print the help subcommand last.
- _os_subcommand_print_help_line(osc, f);
+ _print_subcommand_list(_help_cmd, f);
}
return xit;
static void
_print_header(FILE *f, const char *hdr, bool *already_done)
{
- if (*already_done) {
+ if (already_done && *already_done) {
return;
}
crfprintf_np(f, "");
crfprintf_np(f, "%s:", hdr);
- *already_done = true;
+ crfprintf_np(f, "");
+
+ if (already_done) {
+ *already_done = true;
+ }
}
#pragma mark Module Routines
default:
__builtin_unreachable();
}
+
+ if (!(osco->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_ENUM)) {
+ _stoupper(argbuff);
+ }
} else {
snprintf(optbuff, sizeof(optbuff), "%s", osco->osco_argument_usage);
+ if (!(osco->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_ENUM)) {
+ _stoupper(optbuff);
+ }
}
ret = asprintf(&final, "%s%s", optbuff, argbuff);
default:
__builtin_unreachable();
}
+
+ if (!(osco->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_ENUM)) {
+ _stoupper(argbuff);
+ }
} else {
snprintf(optbuff, sizeof(optbuff), "%s", osco->osco_argument_usage);
+ if (!(osco->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_ENUM)) {
+ _stoupper(optbuff);
+ }
}
ret = asprintf(&final, "%s%s", optbuff, argbuff);
if (osco->osco_option) {
spec_old = spec;
- ret = asprintf(&spec, "%s | -%c", spec, osco->osco_option->val);
+ ret = asprintf(&spec, "-%c | %s", osco->osco_option->val, spec);
if (ret < 0) {
os_assert_zero(ret);
}
// Always include the positional subcommand when printing usage for the
// main subcommand. We do not expect it to be specified in a user-
// provided main subcommand.
+ const os_subcommand_option_t *subopt = &_main_positional[0];
char *__os_free usage_line_old = NULL;
char *__os_free osco_spec = NULL;
usage_line_old = usage_line;
- osco_spec = _os_subcommand_copy_option_spec_long(osc,
- &_main_positional[0]);
+ osco_spec = _os_subcommand_copy_option_spec_long(osc, subopt);
ret = asprintf(&usage_line, "%s <%s>", usage_line, osco_spec);
if (ret < 0) {
os_assert_zero(ret);
const os_subcommand_option_t *osco, FILE *f)
{
char *__os_free opt_spec = NULL;
- ssize_t initpad = -CTL_OUTPUT_OPTARG_PAD;
+ ssize_t initpad = -CTL_OUTPUT_OPTARG_INDENT;
opt_spec = _os_subcommand_copy_option_spec(osc, osco,
OS_SUBCOMMAND_OPTION_SPEC_COMBINED);
- fprintf(f, " %-24s", opt_spec);
+ fprintf(f, " %-24s ", opt_spec);
// If the usage specifier is long, start the description on the next line.
- if (strlen(opt_spec) >= CTL_OUTPUT_OPTARG_PAD) {
- initpad = CTL_OUTPUT_OPTARG_PAD;
+ if (strlen(opt_spec) >= CTL_OUTPUT_OPTARG_OVERFLOW) {
+ initpad = CTL_OUTPUT_OPTARG_INDENT;
crfprintf_np(f, "");
}
- wfprintf_np(f, initpad, CTL_OUTPUT_OPTARG_PAD,
- CTL_OUTPUT_WIDTH, "%s",
+ wfprintf_np(f, initpad, CTL_OUTPUT_OPTARG_INDENT, _ttys->ts_cols, "%s",
osco->osco_argument_human);
}
static void
_os_subcommand_print_help_line(const os_subcommand_t *osc, FILE *f)
{
- ssize_t initpad = -CTL_OUTPUT_OPTARG_PAD;
+ ssize_t initpad = -CTL_OUTPUT_OPTARG_INDENT;
- fprintf(f, " %-24s", osc->osc_name);
+ fprintf(f, " %-24s ", osc->osc_name);
// If the usage specifier is long, start the description on the next line.
- if (strlen(osc->osc_name) >= CTL_OUTPUT_OPTARG_PAD) {
- initpad = CTL_OUTPUT_OPTARG_PAD;
+ if (strlen(osc->osc_name) >= CTL_OUTPUT_OPTARG_OVERFLOW) {
+ initpad = CTL_OUTPUT_OPTARG_INDENT;
crfprintf_np(f, "");
}
- wfprintf_np(f, initpad, CTL_OUTPUT_OPTARG_PAD,
- CTL_OUTPUT_WIDTH, "%s",
+ wfprintf_np(f, initpad, CTL_OUTPUT_OPTARG_INDENT, _ttys->ts_cols, "%s",
osc->osc_desc);
}
bool header_printed = false;
usage_line = _os_subcommand_copy_usage_line(osc);
- wfprintf_np(f, 0, 0, CTL_OUTPUT_WIDTH, "usage: %s", usage_line);
+
+ wfprintf_np(f, 0, 4, _ttys->ts_cols, "USAGE:");
+ crfprintf_np(f, "");
+ wfprintf_np(f, 4, 4, _ttys->ts_cols, "%s", usage_line);
+
+ if (osc->osc_long_desc) {
+ // The long description gets printed in its own paragraph.
+ _print_header(f, "DESCRIPTION", NULL);
+ wfprintf_np(f, 4, 4, _ttys->ts_cols, "%s", osc->osc_long_desc);
+ } else if (osc->osc_desc) {
+ // The short description gets printed on the same line.
+ crfprintf_np(f, "");
+ wfprintf_np(f, 0, 4, _ttys->ts_cols, "DESCRIPTION: %s",
+ osc->osc_desc);
+ }
if (osc->osc_required || osc->osc_positional || osc == _main_cmd) {
i = 0;
OS_SUBCOMMAND_OPTIONS_FOREACH(osco_i, osc, required, i) {
- _print_header(f, "required", &header_printed);
-
- crfprintf_np(f, "");
+ _print_header(f, "REQUIRED", &header_printed);
_os_subcommand_print_option_usage(osc, osco_i, f);
}
i = 0;
OS_SUBCOMMAND_OPTIONS_FOREACH(osco_i, osc, positional, i) {
- _print_header(f, "required", &header_printed);
+ _print_header(f, "REQUIRED", &header_printed);
if (osco_i->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_OPTIONAL_POS) {
continue;
}
- crfprintf_np(f, "");
_os_subcommand_print_option_usage(osc, osco_i, f);
}
if (osc == _main_cmd && osc != _internal_main_cmd) {
// We do not expect the user's main command to specify that a
// subcommand must follow, so always defer to ours.
- _print_header(f, "required", &header_printed);
-
- crfprintf_np(f, "");
+ _print_header(f, "REQUIRED", &header_printed);
_os_subcommand_print_option_usage(osc, &_main_positional[0], f);
}
}
if (osc->osc_optional || osc->osc_positional) {
i = 0;
OS_SUBCOMMAND_OPTIONS_FOREACH(osco_i, osc, optional, i) {
- _print_header(f, "optional", &header_printed);
-
- crfprintf_np(f, "");
+ _print_header(f, "OPTIONAL", &header_printed);
_os_subcommand_print_option_usage(osc, osco_i, f);
}
i = 0;
OS_SUBCOMMAND_OPTIONS_FOREACH(osco_i, osc, positional, i) {
if (osco_i->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_OPTIONAL_POS) {
- _print_header(f, "optional", &header_printed);
-
- crfprintf_np(f, "");
+ _print_header(f, "OPTIONAL", &header_printed);
_os_subcommand_print_option_usage(osc, osco_i, f);
}
}
{
const os_subcommand_t **oscip = NULL;
+ if (!name) {
+ return _main_cmd;
+ }
+
if (strcmp(_help_cmd->osc_name, name) == 0) {
return &__help_cmd;
}
return NULL;
}
+static int
+_os_subcommand_be_helpful(const os_subcommand_t *osc,
+ int argc, const char *argv[])
+{
+ int res = 0;
+
+ if (osc->osc_flags & OS_SUBCOMMAND_FLAG_HELPFUL) {
+ if (argc == 1) {
+ _os_subcommand_print_usage(osc, stdout);
+ res = 1;
+ goto __out;
+ }
+ }
+
+ if (osc->osc_flags & OS_SUBCOMMAND_FLAG_HELPFUL_FIRST_OPTION) {
+ if (argc == 2 && (strcmp(argv[1], "help") == 0 ||
+ strcmp(argv[1], "-h") == 0 ||
+ strcmp(argv[1], "-help") == 0 ||
+ strcmp(argv[1], "--help") == 0)) {
+ _os_subcommand_print_usage(osc, stdout);
+ res = 1;
+ goto __out;
+ }
+ }
+
+__out:
+ return res;
+}
+
+static void
+_print_subcommand_list(const os_subcommand_t *osc, FILE *f)
+{
+ const os_subcommand_t **oscip = NULL;
+ bool header_printed = false;
+
+ LINKER_SET_FOREACH(oscip, const os_subcommand_t **,
+ SUBCOMMAND_LINKER_SET) {
+ const os_subcommand_t *osci = *oscip;
+
+ _print_header(f, "SUBCOMMANDS", &header_printed);
+
+ if ((osci->osc_flags & OS_SUBCOMMAND_FLAG_MAIN) ||
+ (osci->osc_flags & OS_SUBCOMMAND_FLAG_HIDDEN)) {
+ continue;
+ }
+
+ _os_subcommand_print_help_line(osci, f);
+ }
+
+ // Print the help subcommand last.
+ _os_subcommand_print_help_line(osc, f);
+}
+
#pragma mark API
int
os_subcommand_main(int argc, const char *argv[],
const os_subcommand_t *osc = NULL;
const os_subcommand_t **oscip = NULL;
- if (argc < 2) {
- os_subcommand_fprintf(NULL, stderr, "please provide a subcommand");
- xit = EX_USAGE;
- goto __out;
- }
+ _init_column_count();
// Find the main subcommand if any exists. Otherwise we'll just use our pre-
// canned main subcommand.
osc = NULL;
+ // See if we just need to print help for the main command.
+ if (_os_subcommand_be_helpful(_main_cmd, argc, argv)) {
+ _print_subcommand_list(_help_cmd, stdout);
+ xit = 0;
+ goto __out;
+ }
+
// Invoke the main subcommand to snarf any global options. Our default
// implementation does nothing and just returns 0.
xit = _main_cmd->osc_invoke(_main_cmd, argc, argv);
}
}
+ if (_os_subcommand_be_helpful(osc, argc, argv)) {
+ xit = 0;
+ goto __out;
+ }
+
xit = osc->osc_invoke(osc, argc, argv);
} else {
- os_subcommand_fprintf(NULL, stderr, "unknonwn subcommand: %s", cmdname);
+ os_subcommand_fprintf(NULL, stderr, "unknown subcommand: %s", cmdname);
xit = EX_USAGE;
}
__out:
if (xit == EX_USAGE) {
if (!osc) {
- osc = _main_cmd;
+ // If we couldn't find the subcommand, then print the list of known
+ // subcommands.
+ _print_subcommand_list(_help_cmd, stderr);
+ } else {
+ _os_subcommand_print_usage(osc, stderr);
}
-
- _os_subcommand_print_usage(osc, stderr);
}
return xit;
if (!osc || (osc->osc_flags & OS_SUBCOMMAND_FLAG_MAIN)) {
fprintf(f, "%s: ", getprogname());
} else {
- fprintf(f, "%s::%s: ", getprogname(), osc->osc_name);
+ fprintf(f, "%s-%s: ", getprogname(), osc->osc_name);
}
vcrfprintf_np(f, fmt, ap);
if (fd < 0) {
DEBUGPRINT( "Unable to open directory %d:%s => %s\n", parent_fd, path, strerror(errno));
+ free(path);
continue;
}
}
* similar to the PE_parse_boot_argn() kernel routine.
*
* @param which
- * The name of the boot-arg whose value is to be obtained. The caller may pass
- * NULL to simply check for the existence of a boot-arg.
+ * The name of the boot-arg whose value is to be obtained.
*
* @param where
- * On successful return, the integer value of the given boot-arg.
+ * On successful return, the integer value of the given boot-arg. The caller
+ * may pass NULL to simply check for the existence of a boot-arg.
*
* @result
* A Boolean indicating whether the named argument was found. If the discovered
* @const OS_SUBCOMMAND_OPTION_FLAG_OPTIONAL_POS
* The option is a positional option (that is, not identified by a long or short
* flag) and is not required for the subcommand to execute successfully.
+ *
+ * @const OS_SUBCOMMAND_OPTION_FLAG_ENUM
+ * The option has an explicitly-defined list of valid inputs that are enumerated
+ * in the option's {@link osco_argument_usage} field. When printing usage
+ * information for this option, the implementation will not transform the string
+ * in this field in any way.
+ *
+ * For example, an option named "--stream" might have three valid inputs:
+ * "stdin", "stdout", and "stderr", and the usage string may be specified as
+ *
+ * "stdin|stdout|stderr"
+ *
+ * Without this flag, the implementation would print this string as a parameter
+ * name, i.e. in all caps:
+ *
+ * "<STDIN|STDOUT|STDERR>"
+ *
+ * With this flag, the string will be printed as it is given.
*/
DARWIN_API_AVAILABLE_20181020
OS_CLOSED_ENUM(os_subcommand_option_flags, uint64_t,
OS_SUBCOMMAND_OPTION_FLAG_INIT = 0,
OS_SUBCOMMAND_OPTION_FLAG_TERMINATOR = (1 << 0),
OS_SUBCOMMAND_OPTION_FLAG_OPTIONAL_POS = (1 << 1),
+ OS_SUBCOMMAND_OPTION_FLAG_ENUM = (1 << 2),
);
/*!
*
* If multiple subcommands in the same program set
* {@link OS_SUBCOMMAND_FLAG_MAIN}, the implementation's behavior is undefined.
+ *
+ * @const OS_SUBCOMMAND_FLAG_HELPFUL
+ * When invoked with no arguments, this subcommand will print usage information
+ * to stdout and exit with status zero.
+ *
+ * @const OS_SUBCOMMAND_FLAG_HELPFUL_FIRST_OPTION
+ * Allow the implementation to detect whether the user is attempting to print
+ * usage information for the given subcommand. If the implementation concludes
+ * that the user is seeking help, it will print the subcommand's usage
+ * information to stdout and exit with status 0.
+ *
+ * The implementation will conclude that the user is seeking help if
+ *
+ * - only one argument is provided to the subcommand, and
+ *
+ * any of the following
+ *
+ * - the argument is "-h"
+ * - the argument is "-help"
+ * - the argument is "--help"
+ * - the argument is "help"
*/
DARWIN_API_AVAILABLE_20181020
OS_CLOSED_OPTIONS(os_subcommand_flags, uint64_t,
OS_SUBCOMMAND_FLAG_TTYONLY = (1 << 1),
OS_SUBCOMMAND_FLAG_HIDDEN = (1 << 2),
OS_SUBCOMMAND_FLAG_MAIN = (1 << 3),
+ OS_SUBCOMMAND_FLAG_HELPFUL = (1 << 4),
+ OS_SUBCOMMAND_FLAG_HELPFUL_FIRST_OPTION = (1 << 5),
);
/*!
* A brief description of the subcommand. This description will be displayed
* next to the subcommand when the user lists all subcommands.
*
+ * @field osc_long_desc
+ * A long description of the subcommand. This description will be displayed
+ * when the user invokes help on the subcommand. If it's NULL the brief
+ * description from osc_desc will be displayed.
+ *
* @field osc_optstring
* The option string associated with the subcommand. The implementation does not
* recognize this string directly; the intent of storing it here is to provide a
* @field osc_invoke
* The implementation for the subcommand.
*/
-DARWIN_API_AVAILABLE_20191015
+DARWIN_API_AVAILABLE_20200401
struct _os_subcommand {
const os_struct_version_t osc_version;
const os_subcommand_flags_t osc_flags;
const os_subcommand_option_t *osc_optional;
const os_subcommand_option_t *osc_positional;
const os_subcommand_invoke_t osc_invoke;
+ const char *const osc_long_desc;
};
/*!
#define os_calloc(__cnt, __size) ({ \
void *ptr = NULL; \
size_t _size = (__size); \
- size_t _cnt = (__size); \
+ size_t _cnt = (__cnt); \
if ((__builtin_constant_p(__cnt) && __builtin_constant_p(__size)) || \
!_dispatch_is_multithreaded()) { \
ptr = _os_calloc_known(_cnt, _size); \
#include <struct.h>
#include <bootstrap_priv.h>
#include <assert.h>
+#include <sys/ioctl.h>
#include "h/bsd.h"
#include "h/cleanup.h"
* @APPLE_LICENSE_HEADER_END@
*/
+#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <os/bsd.h>
#include <os/stdlib.h>
#include <os/variant_private.h>
+#include <os/boot_mode_private.h>
/*
* Lists all properties overridden by an empty file
#define INTERNAL_DIAGS_PROFILE_PATH "/var/db/ConfigurationProfiles/Settings/com.apple.InternalDiagnostics.plist"
#define FACTORY_CONTENT_PATH "/System/Library/CoreServices/AppleFactoryVariant.plist"
#define BASE_SYSTEM_CONTENT_PATH "/System/Library/BaseSystem"
+#define DARWINOS_CONTENT_PATH "/System/Library/CoreServices/DarwinVariant.plist"
#endif
+static void _check_all_statuses(void);
+
#if !TARGET_OS_SIMULATOR
#define CACHE_SYSCTL_NAME "kern.osvariant_status"
#endif
#if !TARGET_OS_SIMULATOR
static enum check_status can_has_debugger = S_UNKNOWN;
+static enum check_status has_full_logging = S_UNKNOWN;
#if TARGET_OS_IPHONE
static enum check_status internal_release_type = S_UNKNOWN;
static enum check_status factory_release_type = S_UNKNOWN;
static enum check_status internal_diags_profile = S_UNKNOWN;
static enum check_status factory_content = S_UNKNOWN;
static enum check_status base_system_content = S_UNKNOWN;
+static enum check_status darwinos_content = S_UNKNOWN;
#endif // TARGET_OS_IPHONE
#endif // !TARGET_OS_SIMULATOR
static enum check_status is_ephemeral = S_UNKNOWN;
return true;
}
- if (status == 0 && getpid() == 1) {
- /*
- * Looks like we are in launchd; try to set the status.
- *
- * We don't actually care if this works because we'll have warmed our state.
- */
- status = _get_cached_check_status();
- sysctlbyname(CACHE_SYSCTL_NAME, NULL, 0, &status, status_size);
- return true;
- }
-
return false;
}
#endif
-static void _initialize_status(void * __unused ctx)
+static void _initialize_status(void)
{
-#if !TARGET_OS_SIMULATOR
- if (!_load_cached_status()) {
- _parse_disabled_status(NULL);
- }
-#else
- _parse_disabled_status(NULL);
+ static dispatch_once_t once;
+ dispatch_once(&once, ^{
+#if !TARGET_OS_SIMULATOR && !defined(VARIANT_SKIP_EXPORTED)
+ if (_load_cached_status() && !_os_xbs_chrooted) {
+ return;
+ }
#endif
+ _check_all_statuses();
+ });
}
static bool _check_disabled(enum variant_property variant_property)
{
- static dispatch_once_t disabled_status_pred;
- dispatch_once_f(&disabled_status_pred, NULL, _initialize_status);
+ _initialize_status();
return disabled_status[variant_property];
}
#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
-static bool _check_internal_content(void)
+static void _check_internal_content_impl(void)
{
- if (internal_content == S_UNKNOWN) {
+ if (_os_xbs_chrooted && internal_content != S_UNKNOWN) {
+ return;
+ } else {
+ os_assert(internal_content == S_UNKNOWN);
+ }
+
#if !TARGET_OS_SIMULATOR
- const char * path = INTERNAL_CONTENT_PATH;
+ const char * path = INTERNAL_CONTENT_PATH;
#else
- char *simulator_root = getenv("IPHONE_SIMULATOR_ROOT");
- char *to_free = NULL, *path = NULL;
- if (simulator_root) {
- asprintf(&path, "%s/%s", simulator_root, INTERNAL_CONTENT_PATH);
- if (path == NULL) {
- return false;
- }
- to_free = path;
+ char *simulator_root = getenv("IPHONE_SIMULATOR_ROOT");
+ char *to_free = NULL, *path = NULL;
+ if (simulator_root) {
+ asprintf(&path, "%s/%s", simulator_root, INTERNAL_CONTENT_PATH);
+ if (path == NULL) {
+ internal_content = S_NO;
+ return;
}
+ to_free = path;
+ }
#endif
- internal_content = (access(path, F_OK) == 0) ? S_YES : S_NO;
+ internal_content = (access(path, F_OK) == 0) ? S_YES : S_NO;
#if TARGET_OS_SIMULATOR
- free(to_free);
+ free(to_free);
#endif
- }
+}
+
+static bool _check_internal_content(void)
+{
+ _initialize_status();
return status2bool(internal_content);
}
#endif // !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
#if TARGET_OS_OSX
-static bool _check_factory_content(void)
+static void _check_factory_content_impl(void)
{
- if (factory_content == S_UNKNOWN) {
- const char * path = FACTORY_CONTENT_PATH;
- factory_content = (access(path, F_OK) == 0) ? S_YES : S_NO;
+ if (_os_xbs_chrooted && factory_content != S_UNKNOWN) {
+ return;
+ } else {
+ os_assert(factory_content == S_UNKNOWN);
}
+
+ const char * path = FACTORY_CONTENT_PATH;
+ factory_content = (access(path, F_OK) == 0) ? S_YES : S_NO;
+}
+
+static bool _check_factory_content(void)
+{
+ _initialize_status();
+
return status2bool(factory_content);
}
#endif // TARGET_OS_OSX
return true;
}
+
+static void _check_system_version_plist_statuses_impl(void)
+{
+ os_assert(internal_release_type == S_UNKNOWN);
+ os_assert(factory_release_type == S_UNKNOWN);
+ os_assert(darwin_release_type == S_UNKNOWN);
+ os_assert(recovery_release_type == S_UNKNOWN);
+
+ if (!_parse_system_version_plist()) {
+ internal_release_type = (access(INTERNAL_SETTINGS_PATH, F_OK) == 0) ? S_YES : S_NO;
+ factory_release_type = S_NO;
+ darwin_release_type = S_NO;
+ recovery_release_type = S_NO;
+ }
+}
#endif //!TARGET_OS_SIMULATOR
-/*
- * This set of criteria was taken from copyInternalBuild in MobileGestalt.c
- */
static bool _check_internal_release_type(void)
{
#if TARGET_OS_SIMULATOR
return _check_internal_content();
#else // TARGET_OS_SIMULATOR
- if (internal_release_type == S_UNKNOWN) {
- if (!_parse_system_version_plist()) {
- internal_release_type = (access(INTERNAL_SETTINGS_PATH, F_OK) == 0) ? S_YES : S_NO;
- }
- }
+ _initialize_status();
return status2bool(internal_release_type);
#endif // TARGET_OS_SIMULATOR
#if TARGET_OS_SIMULATOR
return false;
#else // TARGET_OS_SIMULATOR
- if (factory_release_type == S_UNKNOWN) {
- if (!_parse_system_version_plist()) {
- factory_release_type = S_NO;
- }
- }
+ _initialize_status();
return status2bool(factory_release_type);
#endif // TARGET_OS_SIMULATOR
#if TARGET_OS_SIMULATOR
return false;
#else // TARGET_OS_SIMULATOR
- if (darwin_release_type == S_UNKNOWN) {
- if (!_parse_system_version_plist()) {
- darwin_release_type = S_NO;
- }
- }
+ _initialize_status();
return status2bool(darwin_release_type);
#endif // TARGET_OS_SIMULATOR
#if TARGET_OS_SIMULATOR
return false;
#else // TARGET_OS_SIMULATOR
- if (recovery_release_type == S_UNKNOWN) {
- if (!_parse_system_version_plist()) {
- recovery_release_type = S_NO;
- }
- }
+ _initialize_status();
return status2bool(recovery_release_type);
#endif // TARGET_OS_SIMULATOR
#else // TARGET_OS_IPHONE
-static bool _check_internal_diags_profile(void)
+static void _check_internal_diags_profile_impl(void)
{
- if (internal_diags_profile == S_UNKNOWN) {
- xpc_object_t profile_settings = read_plist(INTERNAL_DIAGS_PROFILE_PATH);
- if (profile_settings) {
- internal_diags_profile = xpc_dictionary_get_bool(profile_settings, "AppleInternal") ? S_YES : S_NO;
- xpc_release(profile_settings);
- } else {
- internal_diags_profile = S_NO;
- }
+ if (_os_xbs_chrooted && internal_diags_profile != S_UNKNOWN) {
+ return;
+ } else {
+ os_assert(internal_diags_profile == S_UNKNOWN);
}
+ xpc_object_t profile_settings = read_plist(INTERNAL_DIAGS_PROFILE_PATH);
+ if (profile_settings) {
+ internal_diags_profile = xpc_dictionary_get_bool(profile_settings, "AppleInternal") ? S_YES : S_NO;
+ xpc_release(profile_settings);
+ } else {
+ internal_diags_profile = S_NO;
+ }
+}
+
+static bool _check_internal_diags_profile(void)
+{
+ _initialize_status();
+
return status2bool(internal_diags_profile);
}
-static bool _check_base_system_content(void)
+static void _check_base_system_content_impl(void)
{
- if (base_system_content == S_UNKNOWN) {
- const char * path = BASE_SYSTEM_CONTENT_PATH;
- base_system_content = (access(path, F_OK) == 0) ? S_YES : S_NO;
+ if (_os_xbs_chrooted && base_system_content != S_UNKNOWN) {
+ return;
+ } else {
+ os_assert(base_system_content == S_UNKNOWN);
}
+
+ const char * path = BASE_SYSTEM_CONTENT_PATH;
+ base_system_content = (access(path, F_OK) == 0) ? S_YES : S_NO;
+}
+
+static bool _check_base_system_content(void)
+{
+ _initialize_status();
+
return status2bool(base_system_content);
}
+static void _check_darwinos_content_impl(void)
+{
+ if (_os_xbs_chrooted && darwinos_content != S_UNKNOWN) {
+ return;
+ } else {
+ os_assert(darwinos_content == S_UNKNOWN);
+ }
+
+ const char * path = DARWINOS_CONTENT_PATH;
+ darwinos_content = (access(path, F_OK) == 0) ? S_YES : S_NO;
+}
+
+static bool _check_darwinos_content(void)
+{
+ _initialize_status();
+
+ return status2bool(darwinos_content);
+}
+
#endif
#if !TARGET_OS_SIMULATOR
-static bool _check_can_has_debugger(void)
+static void _check_can_has_debugger_impl(void)
{
- if (can_has_debugger == S_UNKNOWN) {
+ if (_os_xbs_chrooted && can_has_debugger != S_UNKNOWN) {
+ return;
+ } else {
+ os_assert(can_has_debugger == S_UNKNOWN);
+ }
+
#if TARGET_OS_IPHONE
- can_has_debugger = *((uint32_t *)_COMM_PAGE_DEV_FIRM) ? S_YES : S_NO;
+ can_has_debugger = *((uint32_t *)_COMM_PAGE_DEV_FIRM) ? S_YES : S_NO;
#else
- /*
- * The comm page bit does exist on macOS, but also requires kernel
- * debugging in the CSR configuration. We don't need to be that strict
- * here.
- */
- can_has_debugger = (csr_check(CSR_ALLOW_APPLE_INTERNAL) == 0) ? S_YES : S_NO;
+ /*
+ * The comm page bit does exist on macOS, but also requires kernel
+ * debugging in the CSR configuration. We don't need to be that strict
+ * here.
+ */
+ can_has_debugger = (csr_check(CSR_ALLOW_APPLE_INTERNAL) == 0) ? S_YES : S_NO;
#endif
- }
+}
+
+static bool _check_can_has_debugger(void)
+{
+ _initialize_status();
+
return status2bool(can_has_debugger);
}
#endif // !TARGET_OS_SIMULATOR
#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-static bool _check_development_kernel(void)
+static void _check_development_kernel_impl(void)
{
- if (development_kernel == S_UNKNOWN) {
- /*
- * Whitelist values from SUPPORTED_KERNEL_CONFIGS.
- */
- char *osbuildconfig = NULL;
- size_t osbuildconfig_sz = 0;
- errno_t err = sysctlbyname_get_data_np("kern.osbuildconfig", (void **)&osbuildconfig, &osbuildconfig_sz);
- if (err == 0) {
- if (strcmp(osbuildconfig, "development") == 0 ||
- strcmp(osbuildconfig, "debug") == 0 ||
- strcmp(osbuildconfig, "profile") == 0 ||
- strcmp(osbuildconfig, "kasan") == 0) {
- development_kernel = S_YES;
- }
+ os_assert(development_kernel == S_UNKNOWN);
+ /*
+ * Whitelist values from SUPPORTED_KERNEL_CONFIGS.
+ */
+ char *osbuildconfig = NULL;
+ size_t osbuildconfig_sz = 0;
+ errno_t err = sysctlbyname_get_data_np("kern.osbuildconfig", (void **)&osbuildconfig, &osbuildconfig_sz);
+ if (err == 0) {
+ if (strcmp(osbuildconfig, "development") == 0 ||
+ strcmp(osbuildconfig, "debug") == 0 ||
+ strcmp(osbuildconfig, "profile") == 0 ||
+ strcmp(osbuildconfig, "kasan") == 0) {
+ development_kernel = S_YES;
}
- free(osbuildconfig);
+ }
+ free(osbuildconfig);
- if (development_kernel == S_UNKNOWN) {
- development_kernel = S_NO;
- }
+ if (development_kernel == S_UNKNOWN) {
+ development_kernel = S_NO;
}
+}
+
+static bool _check_development_kernel(void)
+{
+ _initialize_status();
+
return status2bool(development_kernel);
}
#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+static void _check_uses_ephemeral_storage_impl(void)
+{
+ if (_os_xbs_chrooted && is_ephemeral != S_UNKNOWN) {
+ return;
+ } else {
+ os_assert(is_ephemeral == S_UNKNOWN);
+ }
+
+ uint32_t buffer = 0;
+ size_t buffer_size = sizeof(buffer);
+
+ sysctlbyname("hw.ephemeral_storage", (void *)&buffer, &buffer_size, NULL, 0);
+
+ is_ephemeral = (buffer != 0) ? S_YES : S_NO;
+}
+
+static bool _check_uses_ephemeral_storage(void)
+{
+ _initialize_status();
+
+ return status2bool(is_ephemeral);
+}
+
+#if !TARGET_OS_SIMULATOR
+// internal upcall into libtrace
+extern bool
+_os_trace_basesystem_storage_available(void);
+
+static void
+_init_has_full_logging(void)
+{
+#if TARGET_OS_OSX
+ if (_check_base_system_content() &&
+ !_os_trace_basesystem_storage_available()) {
+ has_full_logging = S_NO;
+ return;
+ }
+#endif
+
+ has_full_logging = S_YES;
+}
+
+static bool _check_has_full_logging(void)
+{
+ _initialize_status();
+
+ return status2bool(has_full_logging);
+}
+#endif // !TARGET_OS_SIMULATOR
+
+static void _check_all_statuses(void)
+{
+#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+ _check_internal_content_impl();
+#endif
+
+ _check_uses_ephemeral_storage_impl();
+
+#if !TARGET_OS_SIMULATOR
+ _check_can_has_debugger_impl();
+
+#if TARGET_OS_IPHONE
+ _check_system_version_plist_statuses_impl();
+ _check_development_kernel_impl();
+#else
+ _check_internal_diags_profile_impl();
+ _check_factory_content_impl();
+ _check_base_system_content_impl();
+ _check_darwinos_content_impl();
+#endif
+
+#endif // !TARGET_OS_SIMULUATOR
+
+ _parse_disabled_status(NULL);
+}
+
+static bool
+os_variant_has_full_logging(const char * __unused subsystem)
+{
+#if TARGET_OS_SIMULATOR
+ return true;
+#else
+ return _check_has_full_logging();
+#endif
+}
+
+static const variant_check_mapping _variant_map[] = {
+ {.variant = "AllowsInternalSecurityPolicies", .function = os_variant_allows_internal_security_policies},
+ {.variant = "HasFactoryContent", .function = os_variant_has_factory_content},
+ {.variant = "HasFullLogging", .function = os_variant_has_full_logging},
+ {.variant = "HasInternalContent", .function = os_variant_has_internal_content},
+ {.variant = "HasInternalDiagnostics", .function = os_variant_has_internal_diagnostics},
+ {.variant = "HasInternalUI", .function = os_variant_has_internal_ui},
+#if TARGET_OS_OSX
+ {.variant = "IsBaseSystem", .function = os_variant_is_basesystem},
+#endif
+ {.variant = "IsDarwinOS", .function = os_variant_is_darwinos},
+ {.variant = "IsRecovery", .function = os_variant_is_recovery},
+ {.variant = "UsesEphemeralStorage", .function = os_variant_uses_ephemeral_storage},
+ {.variant = NULL, .function = NULL}
+};
+
// For unit tests
#ifndef VARIANT_SKIP_EXPORTED
bool
os_variant_is_darwinos(const char * __unused subsystem)
{
-
#if TARGET_OS_IPHONE
return _check_darwin_release_type();
#else
- return false;
+ return _check_darwinos_content();
#endif
}
#endif
}
+#if TARGET_OS_OSX
bool
-os_variant_uses_ephemeral_storage(const char * __unused subsystem)
+os_variant_is_basesystem(const char * __unused subsystem)
{
- if (is_ephemeral == S_UNKNOWN) {
- uint32_t buffer = 0;
- size_t buffer_size = sizeof(buffer);
-
- sysctlbyname("hw.ephemeral_storage", (void *)&buffer, &buffer_size, NULL, 0);
-
- is_ephemeral = (buffer != 0) ? S_YES : S_NO;
- }
+ return _check_base_system_content();
+}
+#endif
- return status2bool(is_ephemeral);
+bool
+os_variant_uses_ephemeral_storage(const char * __unused subsystem)
+{
+ return _check_uses_ephemeral_storage();
}
bool
-os_variant_check(const char * __unused subsystem, const char *variant)
-{
- static const variant_check_mapping map[] = {
- {.variant = "HasInternalContent", .function = os_variant_has_internal_content},
- {.variant = "HasInternalDiagnostics", .function = os_variant_has_internal_diagnostics},
- {.variant = "HasInternalUI", .function = os_variant_has_internal_ui},
- {.variant = "AllowsInternalSecurityPolicies", .function = os_variant_allows_internal_security_policies},
- {.variant = "HasFactoryContent", .function = os_variant_has_factory_content},
- {.variant = "IsDarwinOS", .function = os_variant_is_darwinos},
- {.variant = "UsesEphemeralStorage", .function = os_variant_uses_ephemeral_storage},
- {.variant = "IsRecovery", .function = os_variant_is_recovery},
- {.variant = NULL, .function = NULL}
- };
- variant_check_mapping *current = (variant_check_mapping *)map;
+os_variant_check(const char *subsystem, const char *variant)
+{
+ variant_check_mapping *current = (variant_check_mapping *)_variant_map;
while (current->variant) {
if (0 == strncasecmp(current->variant, variant, strlen(current->variant))) {
- return current->function("");
+ return current->function(subsystem);
}
current ++;
}
return false;
}
+char *
+os_variant_copy_description(const char *subsystem)
+{
+ variant_check_mapping *current = (variant_check_mapping *)_variant_map;
+
+ char *desc = NULL;
+ size_t desc_size = 0;
+ FILE *outstream = open_memstream(&desc, &desc_size);
+ if (!outstream) {
+ return NULL;
+ }
+
+ int error = 0;
+ bool needs_space = false;
+ while (current->variant) {
+ if (current->function(subsystem)) {
+ if (needs_space) {
+ int written = fputc(' ', outstream);
+ if (written == EOF) {
+ error = errno;
+ goto error_out;
+ }
+ }
+ int written = fputs(current->variant, outstream);
+ if (written == EOF) {
+ error = errno;
+ goto error_out;
+ }
+ needs_space = true;
+ }
+ current++;
+ }
+
+ int closed = fclose(outstream);
+ if (closed == EOF) {
+ error = errno;
+ goto close_error_out;
+ }
+ return desc;
+
+error_out:
+ (void)fclose(outstream);
+close_error_out:
+ free(desc);
+ errno = error;
+ return NULL;
+}
+
+#if TARGET_OS_OSX
+
+// XXX As an implementation detail, os_boot_mode is piggy-backing on
+// os_variant's infrastructure. This is not necessarily its long-term home,
+// particularly after rdar://59966472
+
+static enum boot_mode {
+ BOOTMODE_UNKNOWN = 0,
+ BOOTMODE_NONE,
+ BOOTMODE_FVUNLOCK,
+ BOOTMODE_KCGEN,
+ BOOTMODE_DIAGNOSTICS,
+ BOOTMODE_MIGRATION,
+} os_boot_mode;
+
+static void
+_os_boot_mode_launchd_init(const char *boot_mode)
+{
+ if (boot_mode == NULL) {
+ os_boot_mode = BOOTMODE_NONE;
+ } else if (strcmp(boot_mode, OS_BOOT_MODE_FVUNLOCK) == 0) {
+ os_boot_mode = BOOTMODE_FVUNLOCK;
+ } else if (strcmp(boot_mode, OS_BOOT_MODE_KCGEN) == 0) {
+ os_boot_mode = BOOTMODE_KCGEN;
+ } else if (strcmp(boot_mode, OS_BOOT_MODE_DIAGNOSTICS) == 0) {
+ os_boot_mode = BOOTMODE_DIAGNOSTICS;
+ } else if (strcmp(boot_mode, OS_BOOT_MODE_MIGRATION) == 0) {
+ os_boot_mode = BOOTMODE_MIGRATION;
+ }
+}
+
+bool
+os_boot_mode_query(const char **boot_mode_out)
+{
+ _initialize_status();
+
+ switch (os_boot_mode) {
+ case BOOTMODE_NONE:
+ *boot_mode_out = NULL;
+ return true;
+ case BOOTMODE_FVUNLOCK:
+ *boot_mode_out = OS_BOOT_MODE_FVUNLOCK;
+ return true;
+ case BOOTMODE_KCGEN:
+ *boot_mode_out = OS_BOOT_MODE_KCGEN;
+ return true;
+ case BOOTMODE_DIAGNOSTICS:
+ *boot_mode_out = OS_BOOT_MODE_DIAGNOSTICS;
+ return true;
+ case BOOTMODE_MIGRATION:
+ *boot_mode_out = OS_BOOT_MODE_MIGRATION;
+ return true;
+ default:
+ return false;
+ }
+}
+
+#endif // TARGET_OS_OSX
+
+void
+os_variant_init_4launchd(const char *boot_mode)
+{
+#if TARGET_OS_SIMULATOR
+ os_crash("simulator launchd does not initialize os_variant");
+#else
+ os_assert(getpid() == 1);
+
+ _init_has_full_logging();
+
+#if TARGET_OS_OSX
+ _os_boot_mode_launchd_init(boot_mode);
+#endif
+
+ // re-initialize disabled status even if we've already initialized
+ // previously, as it's possible we may have initialized before the override
+ // file was available to read
+ _parse_disabled_status(NULL);
+
+ uint64_t status = _get_cached_check_status();
+ size_t status_size = sizeof(status);
+ // TODO: assert that this succeeds
+ sysctlbyname(CACHE_SYSCTL_NAME, NULL, 0, &status, status_size);
+#endif
+}
+
#endif // VARIANT_SKIP_EXPORTED
+/*
+ * Bit allocation in kern.osvariant_status (all ranges inclusive):
+ * - [0-27] are 2-bit check_status values
+ * - [28-31] are 0xF
+ * - [32-32+VP_MAX-1] encode variant_property booleans
+ * - [48-51] encode the boot mode, if known
+ * - [60-62] are 0x7
+ */
#define STATUS_INITIAL_BITS 0x70000000F0000000ULL
#define STATUS_BIT_WIDTH 2
#define STATUS_SET 0x2
SFP_RECOVERY_RELEASE_TYPE = 8,
SFP_BASE_SYSTEM_CONTENT = 9,
SFP_DEVELOPMENT_KERNEL = 10,
+ SFP_DARWINOS_CONTENT = 11,
+ SFP_FULL_LOGGING = 12,
};
+#define STATUS_BOOT_MODE_SHIFT 48
+#define STATUS_BOOT_MODE_MASK 0x000F000000000000ULL
+
#if !TARGET_OS_SIMULATOR
static uint64_t _get_cached_check_status(void)
{
+ _initialize_status();
+
uint64_t res = STATUS_INITIAL_BITS;
#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
- _check_internal_content();
- if (internal_content != S_UNKNOWN)
- res |= internal_content << SFP_INTERNAL_CONTENT * STATUS_BIT_WIDTH;
+ os_assert(internal_content != S_UNKNOWN);
+ res |= internal_content << SFP_INTERNAL_CONTENT * STATUS_BIT_WIDTH;
#endif
- _check_can_has_debugger();
- if (can_has_debugger != S_UNKNOWN)
- res |= can_has_debugger << SFP_CAN_HAS_DEBUGGER * STATUS_BIT_WIDTH;
+ os_assert(can_has_debugger != S_UNKNOWN);
+ res |= can_has_debugger << SFP_CAN_HAS_DEBUGGER * STATUS_BIT_WIDTH;
- (void)os_variant_uses_ephemeral_storage("");
- if (is_ephemeral != S_UNKNOWN)
- res |= is_ephemeral << SFP_EPHEMERAL_VOLUME * STATUS_BIT_WIDTH;
+ os_assert(is_ephemeral != S_UNKNOWN);
+ res |= is_ephemeral << SFP_EPHEMERAL_VOLUME * STATUS_BIT_WIDTH;
+
+#ifdef VARIANT_SKIP_EXPORTED
+ // has_full_logging can't be computed outside launchd, so in the tests/etc.
+ // cheat and use the value reported by libdarwin rather than re-computing
+ has_full_logging = os_variant_check("com.apple.Libc.tests", "HasFullLogging") ?
+ S_YES : S_NO;
+#else
+ os_assert(has_full_logging != S_UNKNOWN);
+#endif
+ res |= has_full_logging << SFP_FULL_LOGGING * STATUS_BIT_WIDTH;
#if TARGET_OS_IPHONE
- _check_internal_release_type();
- if (internal_release_type != S_UNKNOWN)
- res |= internal_release_type << SFP_INTERNAL_RELEASE_TYPE * STATUS_BIT_WIDTH;
+ os_assert(internal_release_type != S_UNKNOWN);
+ res |= internal_release_type << SFP_INTERNAL_RELEASE_TYPE * STATUS_BIT_WIDTH;
- _check_factory_release_type();
- if (factory_release_type != S_UNKNOWN)
- res |= factory_release_type << SFP_FACTORY_RELEASE_TYPE * STATUS_BIT_WIDTH;
+ os_assert(factory_release_type != S_UNKNOWN);
+ res |= factory_release_type << SFP_FACTORY_RELEASE_TYPE * STATUS_BIT_WIDTH;
- _check_darwin_release_type();
- if (darwin_release_type != S_UNKNOWN)
- res |= darwin_release_type << SFP_DARWINOS_RELEASE_TYPE * STATUS_BIT_WIDTH;
+ os_assert(darwin_release_type != S_UNKNOWN);
+ res |= darwin_release_type << SFP_DARWINOS_RELEASE_TYPE * STATUS_BIT_WIDTH;
- _check_recovery_release_type();
- if (recovery_release_type != S_UNKNOWN)
- res |= recovery_release_type << SFP_RECOVERY_RELEASE_TYPE * STATUS_BIT_WIDTH;
+ os_assert(recovery_release_type != S_UNKNOWN);
+ res |= recovery_release_type << SFP_RECOVERY_RELEASE_TYPE * STATUS_BIT_WIDTH;
- _check_development_kernel();
- if (development_kernel != S_UNKNOWN)
- res |= development_kernel << SFP_DEVELOPMENT_KERNEL * STATUS_BIT_WIDTH;
+ os_assert(development_kernel != S_UNKNOWN);
+ res |= development_kernel << SFP_DEVELOPMENT_KERNEL * STATUS_BIT_WIDTH;
#else
- _check_internal_diags_profile();
- if (internal_diags_profile != S_UNKNOWN)
- res |= internal_diags_profile << SFP_INTERNAL_DIAGS_PROFILE * STATUS_BIT_WIDTH;
+ os_assert(internal_diags_profile != S_UNKNOWN);
+ res |= internal_diags_profile << SFP_INTERNAL_DIAGS_PROFILE * STATUS_BIT_WIDTH;
+
+ os_assert(factory_content != S_UNKNOWN);
+ res |= factory_content << SFP_FACTORY_CONTENT * STATUS_BIT_WIDTH;
- _check_factory_content();
- if (factory_content != S_UNKNOWN)
- res |= factory_content << SFP_FACTORY_CONTENT * STATUS_BIT_WIDTH;
+ os_assert(base_system_content != S_UNKNOWN);
+ res |= base_system_content << SFP_BASE_SYSTEM_CONTENT * STATUS_BIT_WIDTH;
- _check_base_system_content();
- if (base_system_content != S_UNKNOWN)
- res |= base_system_content << SFP_BASE_SYSTEM_CONTENT * STATUS_BIT_WIDTH;
+ os_assert(darwinos_content != S_UNKNOWN);
+ res |= darwinos_content << SFP_DARWINOS_CONTENT * STATUS_BIT_WIDTH;
#endif
- _parse_disabled_status(NULL);
for (int i = 0; i < VP_MAX; i++) {
if (disabled_status[i]) {
res |= 0x1ULL << (i + 32);
}
}
+#if !defined(VARIANT_SKIP_EXPORTED) && TARGET_OS_OSX
+ res |= ((uint64_t)os_boot_mode) << STATUS_BOOT_MODE_SHIFT;
+#endif // TARGET_OS_OSX
+
return res;
}
if ((status >> (SFP_EPHEMERAL_VOLUME * STATUS_BIT_WIDTH)) & STATUS_SET)
is_ephemeral = (status >> (SFP_EPHEMERAL_VOLUME * STATUS_BIT_WIDTH)) & STATUS_MASK;
+ if ((status >> (SFP_FULL_LOGGING * STATUS_BIT_WIDTH)) & STATUS_SET)
+ has_full_logging = (status >> (SFP_FULL_LOGGING * STATUS_BIT_WIDTH)) & STATUS_MASK;
+
#if TARGET_OS_IPHONE
if ((status >> (SFP_INTERNAL_RELEASE_TYPE * STATUS_BIT_WIDTH)) & STATUS_SET)
internal_release_type = (status >> (SFP_INTERNAL_RELEASE_TYPE * STATUS_BIT_WIDTH)) & STATUS_MASK;
if ((status >> (SFP_BASE_SYSTEM_CONTENT * STATUS_BIT_WIDTH)) & STATUS_SET)
base_system_content = (status >> (SFP_BASE_SYSTEM_CONTENT * STATUS_BIT_WIDTH)) & STATUS_MASK;
+
+ if ((status >> (SFP_DARWINOS_CONTENT * STATUS_BIT_WIDTH)) & STATUS_SET)
+ darwinos_content = (status >> (SFP_DARWINOS_CONTENT * STATUS_BIT_WIDTH)) & STATUS_MASK;
#endif
for (int i = 0; i < VP_MAX; i++) {
disabled_status[i] = (status >> (32 + i)) & 0x1;
}
+
+#if !defined(VARIANT_SKIP_EXPORTED) && TARGET_OS_OSX
+ os_boot_mode = (enum boot_mode)((status & STATUS_BOOT_MODE_MASK) >> STATUS_BOOT_MODE_SHIFT);
+#endif // TARGET_OS_OSX
}
#endif // !TARGET_OS_SIMULATOR
return NULL;
}
-__private_extern__ void
+/*
+* This is provided for programs (like grep) that are calling this
+* private function. This is also used by wcscoll()
+*/
+void
__collate_lookup_l(const wchar_t *t, int *len, int *prim, int *sec, locale_t loc)
{
struct __collate_st_chain_pri *p2;
int l;
+ if (!*t) {
+ *len = 0;
+ *prim = 0;
+ *sec = 0;
+ return;
+ }
+
+ NORMALIZE_LOCALE(loc);
+ if (loc->__collate_load_error) {
+ *len = 1;
+ *prim = *t;
+ *sec = 0;
+ return;
+ }
+
*len = 1;
*prim = *sec = 0;
p2 = chainsearch(t, &l, loc);
}
/*
- * This is only provided for programs (like grep) that are calling this
- * private function. This will go away eventually.
+ * This is also provided for programs (like grep) that are calling this
+ * private function - that do not perform their own multi-byte handling.
+ * This will go away eventually.
*/
void
__collate_lookup(const unsigned char *t, int *len, int *prim, int *sec)
{
locale_t loc = __current_locale();
- wchar_t *w = __collate_mbstowcs((const char *)t, loc);
+ wchar_t *w = NULL;
int sverrno;
+ if (!*t) {
+ *len = 0;
+ *prim = 0;
+ *sec = 0;
+ return;
+ }
+
+ if (loc->__collate_load_error || (w = __collate_mbstowcs((const char *)t, loc)) == NULL) {
+ *len = 1;
+ *prim = (int)*t;
+ *sec = 0;
+
+ sverrno = errno;
+ free((void*)w);
+ errno = sverrno;
+ return;
+ }
+
__collate_lookup_l(w, len, prim, sec, loc);
sverrno = errno;
free(w);
errno = sverrno;
}
-
+
__private_extern__ void
__collate_lookup_which(const wchar_t *t, int *len, int *pri, int which, locale_t loc)
{
bstring.3 bstring.3
btowc.3 btowc.3 wctob.3 btowc_l.3 wctob_l.3
btree.3 btree.3
-byteorder.3 byteorder.3 htonl.3 htons.3 ntohl.3 ntohs.3
+byteorder.3 byteorder.3 htonl.3 htons.3 ntohl.3 ntohs.3 htonll.3 ntohll.3
bzero.3 bzero.3
catclose.3 catclose.3
catgets.3 catgets.3
posix_memalign.3 posix_memalign.3
printf.3 printf.3 asprintf.3 dprintf.3 fprintf.3 snprintf.3 sprintf.3 vasprintf.3 vdprintf.3 vfprintf.3 vprintf.3 vsnprintf.3 vsprintf.3
printf_l.3 printf_l.3 asprintf_l.3 fprintf_l.3 snprintf_l.3 sprintf_l.3 vasprintf_l.3 vfprintf_l.3 vprintf_l.3 vsnprintf_l.3 vsprintf_l.3
-psignal.3 psignal.3 sys_siglist.3 sys_signame.3 strsignal.3 sys_siglist.3 sys_signame.3
+psignal.3 psignal.3 sys_siglist.3 sys_signame.3 strsignal.3 strsignal_r.3 sys_siglist.3 sys_signame.3
psort.3 psort.3 psort_b.3 psort_r.3
putc.3 putc.3 fputc.3 putc_unlocked.3 putchar.3 putchar_unlocked.3 putw.3
putwc.3 putwc.3 fputwc.3 putwchar.3
strtok.3 strtok.3 strtok_r.3
strtol.3 strtol.3 strtoll.3 strtoq.3 strtoimax.3
strtol_l.3 strtol_l.3 strtoimax_l.3 strtoll_l.3 strtoq_l.3 strtoul_l.3 strtoull_l.3 strtoumax_l.3 strtouq_l.3
+strtonum.3 strtonum.3
strtoul.3 strtoul.3 strtoull.3 strtoumax.3 strtouq.3
strxfrm.3 strxfrm.3 strxfrm_l.3
style.3 style.3
.Sh NAME
.Nm htonl ,
.Nm htons ,
+.Nm htonll ,
.Nm ntohl ,
-.Nm ntohs
+.Nm ntohs ,
+.Nm ntohll
.Nd convert values between host and network byte order
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
.In arpa/inet.h
+.Ft uint64_t
+.Fn htonll "uint64_t hostlonglong"
.Ft uint32_t
.Fn htonl "uint32_t hostlong"
.Ft uint16_t
.Fn htons "uint16_t hostshort"
+.Ft uint64_t
+.Fn ntohll "uint64_t netlonglong"
.Ft uint32_t
.Fn ntohl "uint32_t netlong"
.Ft uint16_t
.Fn ntohs "uint16_t netshort"
.Sh DESCRIPTION
-These routines convert 16 and 32 bit quantities between network
+These routines convert 16 bit, 32 bit, and 64 bit quantities between network
byte order and host byte order.
(Network byte order is big endian, or most significant byte first.)
On machines which have a byte order which is the same as the network
.Sh STANDARDS
The
.Nm byteorder
-functions are expected to conform with IEEE Std POSIX.1-200x
-.Pq Dq POSIX.1 .
+functions except
+.Nm htonll
+and
+.Nm ntohll
+are expected to conform with IEEE Std POSIX.1-200x
+.Pq Dq POSIX.1
.Sh HISTORY
The
-.Nm byteorder
-functions appeared in
+functions
+.Nm htonl,
+.Nm htons,
+.Nm ntohl,
+.Nm ntohs
+appeared in
.Bx 4.2 .
+.Pp
+The functions
+.Nm htonll
+and
+.Nm ntohll
+first appeared in OS X 10.10 (Yosemite).
.Sh BUGS
On the
.Tn VAX
* individual preprocessor macros in this header that declare new behavior as
* required.
*/
-#define DARWIN_API_VERSION 20191015u
+#define DARWIN_API_VERSION 20200526u
#if !DARWIN_BUILDING_LIBSYSTEM_DARWIN
#define DARWIN_API_AVAILABLE_20170407 \
API_AVAILABLE(macos(10.15.2), ios(13.3), tvos(13.3), watchos(6.1.1))
#define DARWIN_API_AVAILABLE_20191015 \
API_AVAILABLE(macos(10.15.2), ios(13.3), tvos(13.3), watchos(6.1.1))
+#define DARWIN_API_AVAILABLE_20200220 \
+ API_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0))
+#define DARWIN_API_AVAILABLE_20200401 \
+ API_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0))
+#define DARWIN_API_AVAILABLE_20200526 \
+ API_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0))
#else
#define DARWIN_API_AVAILABLE_20170407
#define DARWIN_API_AVAILABLE_20180727
#define DARWIN_API_AVAILABLE_20181020
#define DARWIN_API_AVAILABLE_20190830
#define DARWIN_API_AVAILABLE_20191015
+#define DARWIN_API_AVAILABLE_20200220
+#define DARWIN_API_AVAILABLE_20200401
+#define DARWIN_API_AVAILABLE_20200526
#endif
/*!
#define os_constant(x) __builtin_constant_p((x))
#define os_hardware_trap() __asm__ __volatile__ (""); __builtin_trap()
#define __OS_COMPILETIME_ASSERT__(e) __extension__({ \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wvla\"") \
char __compile_time_assert__[(e) ? 1 : -1]; \
(void)__compile_time_assert__; \
+ _Pragma("clang diagnostic pop") \
})
#else /* __GNUC__ */
#define os_constant(x) ((long)0)
--- /dev/null
+/*
+ * Copyright (c) 2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+#ifndef __OS_BOOT_MODE_H__
+#define __OS_BOOT_MODE_H__
+
+#include <stdbool.h>
+
+#include <os/base.h>
+#include <os/availability.h>
+
+__BEGIN_DECLS
+
+#define OS_BOOT_MODE_FVUNLOCK "fvunlock"
+#define OS_BOOT_MODE_KCGEN "kcgen"
+#define OS_BOOT_MODE_DIAGNOSTICS "diagnostics"
+#define OS_BOOT_MODE_MIGRATION "migration"
+
+/*!
+ * @function os_boot_mode_query
+ *
+ * @abstract fetches the current boot mode if available
+ *
+ * @description
+ * This attempts to query the current boot mode.
+ *
+ * In general, please prefer the _LimitLoad[To|From]BootMode launchd plist key
+ * over direct use of this SPI.
+ *
+ * CAVEATS:
+ * - this is not guaranteed to succeed when called from boot tasks (we may not
+ * have figured out our boot mode yet)
+ * - though the boot mode can in principle be an arbitrary string, this can
+ * currently only be used to query for the "fvunlock", "kcgen", "diagnostics",
+ * and "migration" boot modes
+ *
+ * @result
+ * true if the query succeeds, with boot_mode_out set to the boot mode string
+ * (or NULL if no particular boot mode). false if the boot mode is not known,
+ * in which case boot_mode_out is not modified.
+ */
+API_AVAILABLE(macosx(10.16)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos)
+OS_EXPORT OS_WARN_RESULT
+bool
+os_boot_mode_query(const char **boot_mode_out);
+
+__END_DECLS
+
+#endif // __OS_BOOT_MODE_H__
* The following macros are used to declare global sets of objects, which
* are collected by the linker into a `linker set' as defined below.
* For Mach-O, this is done by constructing a separate segment inside the
- * __DATA section for each set. The contents of this segment are an array
+ * __DATA_CONST section for each set. The contents of this segment are an array
* of pointers to the objects in the set.
*
* Note that due to limitations of the Mach-O format, there cannot
# include <mach-o/getsect.h>
# include <mach-o/loader.h>
# include <mach-o/dyld.h>
+# include <crt_externs.h>
# if __LP64__
# define MACH_HEADER_TYPE struct mach_header_64
# endif
#endif
+#if __LP64__ && !(__x86_64__ || __i386__)
+# define LINKER_SET_ENTRY_PACKED
+# define LINKER_SET_SEGMENT __DATA_CONST
+# define LINKER_SET_SEGMENT_CSTR "__DATA_CONST"
+#else
+# define LINKER_SET_ENTRY_PACKED __attribute__((packed))
+# define LINKER_SET_SEGMENT __DATA
+# define LINKER_SET_SEGMENT_CSTR "__DATA"
+#endif
/*
* Private macros, not to be used outside this header file.
* The objective of this macro stack is to produce the following output,
* given SET and SYM as arguments:
*
- * void const * __set_SET_sym_SYM __attribute__((section("__DATA,SET"))) = & SYM
+ * void const * __set_SET_sym_SYM __attribute__((section("__DATA_CONST,SET"))) = & SYM
*/
/* Wrap entries in a type that can be blacklisted from KASAN */
struct linker_set_entry {
void *ptr;
-} __attribute__((packed));
+} LINKER_SET_ENTRY_PACKED;
#ifdef __LS_VA_STRINGIFY__
# undef __LS_VA_STRINGIFY__
#define __LS_VA_STRCONCAT(_x, _y) __LS_VA_STRINGIFY(_x,_y)
#define __LINKER_MAKE_SET(_set, _sym) \
/*__unused*/ /*static*/ const struct linker_set_entry /*const*/ __set_##_set##_sym_##_sym \
- __attribute__ ((section(__LS_VA_STRCONCAT(__DATA,_set)),used)) = { (void *)&_sym }
+ __attribute__ ((section(__LS_VA_STRCONCAT(LINKER_SET_SEGMENT,_set)),used)) = { (void *)&_sym }
/* the line above is very fragile - if your compiler breaks linker sets,
* just play around with "static", "const", "used" etc. :-) */
}
return 0;
#else
+ (void)_header;
return 0;
#endif
}
static __inline void **
__linker_set_object_begin(MACH_HEADER_TYPE *_header, const char *_set)
{
- void *_set_begin;
+ char *_set_begin;
SECTDATA_SIZE_TYPE _size;
- _set_begin = GETSECTIONDATA_VARIANT(_header, "__DATA", _set, &_size);
+ _set_begin = (char *)GETSECTIONDATA_VARIANT(_header, LINKER_SET_SEGMENT_CSTR, _set, &_size);
_set_begin += __linker_get_slide((struct mach_header *)_header);
- return (void **) _set_begin;
+ return (void **)(uintptr_t)_set_begin;
}
static __inline void **
static __inline void **
__linker_set_object_limit(MACH_HEADER_TYPE *_header, const char *_set)
{
- void *_set_begin;
+ char *_set_begin;
SECTDATA_SIZE_TYPE _size;
- _set_begin = GETSECTIONDATA_VARIANT(_header, "__DATA", _set, &_size);
+ _set_begin = (char *)GETSECTIONDATA_VARIANT(_header, LINKER_SET_SEGMENT_CSTR, _set, &_size);
_set_begin += __linker_get_slide((struct mach_header *)_header);
return (void **) ((uintptr_t) _set_begin + _size);
/*!
* @function os_variant_uses_ephemeral_storage
*
- * @abstract returns whether the system is booted from an ephermeral volume
+ * @abstract returns whether the system is booted from an ephemeral volume
*
* @result
* Returns true if the system is booted with ephemeral storage for the data volume.
bool
os_variant_uses_ephemeral_storage(const char *subsystem);
+/*!
+ * @function os_variant_is_basesystem
+ *
+ * @abstract returns whether this system variant is the macOS BaseSystem
+ *
+ * @description
+ * On macOS, this returns whether the running environment is the BaseSystem.
+ *
+ * The macOS BaseSystem is used for Recovery, Installer, Diagnostics, FileVault
+ * unlock, and more. This will return true on all of these.
+ *
+ * @result
+ * Returns true if this variant is BaseSystem
+ */
+API_AVAILABLE(macosx(10.16)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos)
+OS_EXPORT OS_WARN_RESULT
+bool
+os_variant_is_basesystem(const char *subsystem);
+
/*!
* @function os_variant_is_recovery
*
* @abstract returns whether this system variant is the recovery OS.
*
* @description
- * On macOS, this returns whether the running environment is the BaseSystem.
- * This will be true in the installer and recovery environments. On embedded
- * platforms, this returns whether this is the NeRD (Network Recovery on
- * Device) OS.
+ * On macOS, this returns whether the running environment is the BaseSystem, in
+ * a mode where it is independent of a running operating system. This includes
+ * the installer, local and internet recovery, and diagnostics. It does not
+ * include modes where the BaseSystem is acting as a mode of the primary OS,
+ * such as FileVault unlock.
+ *
+ * NOTE: this is currently not implemented and simply returns
+ * os_variant_is_basesystem() until it can be implemented.
+ *
+ * On embedded platforms, this returns whether this is the NeRD (Network
+ * Recovery on Device) OS. It returns false in the restore/OTA ramdisks.
*
* @result
* Returns true if this variant is a recoveryOS
*/
-API_AVAILABLE(macosx(10.15), ios(13.0), tvos(13.0), watchos(6.0))
+API_AVAILABLE(macosx(10.15), ios(13.0), tvos(13.0), watchos(6.0), bridgeos(4.0))
OS_EXPORT OS_WARN_RESULT
bool
os_variant_is_recovery(const char *subsystem);
* @result
* Returns true if the system is of the specified variant.
*/
-API_AVAILABLE(macosx(10.15), ios(13.0), tvos(13.0), watchos(6.0))
+API_AVAILABLE(macosx(10.15), ios(13.0), tvos(13.0), watchos(6.0), bridgeos(4.0))
OS_EXPORT OS_WARN_RESULT
bool
os_variant_check(const char *subsystem, const char *variant);
+/*!
+ * @function os_variant_copy_description
+ *
+ * @abstract returns a string describing the current variants
+ *
+ * @description
+ * This returns a string containing the variants of the current system.
+ *
+ * @result
+ * Returns a string that must be freed by the caller if successful. If an
+ * error occurs, @c NULL is returned and @c errno will be set to indicate the
+ * error.
+ */
+API_AVAILABLE(macosx(10.16), ios(14.0), tvos(13.0), watchos(7.0), bridgeos(4.0))
+OS_EXPORT OS_WARN_RESULT
+char *
+os_variant_copy_description(const char *subsystem);
+
+OS_EXPORT
+void
+os_variant_init_4launchd(const char *boot_mode);
+
__END_DECLS
#endif // __os_variant_H__
fclose(FILE *fp)
{
int r;
+ int error = 0;
pthread_once(&__sdidinit, __sinit);
}
FLOCKFILE(fp);
r = __sflush(fp);
- if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0)
+ if (r < 0) {
+ error = errno;
+ }
+ if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) {
r = EOF;
+ error = errno;
+ }
if (fp->_flags & __SMBF)
free((char *)fp->_bf._base);
if (HASUB(fp))
fp->_r = fp->_w = 0; /* Mess up if reaccessed. */
FUNLOCKFILE(fp);
__sfprelease(fp); /* Release this FILE for reuse. */
+ /* Don't clobber errno unnecessarily. */
+ if (error) {
+ errno = error;
+ }
return (r);
}
pthread_once_t __sdidinit;
-#if !TARGET_OS_EMBEDDED
+#if !TARGET_OS_IPHONE
#define NDYNAMIC 10 /* add ten more whenever necessary */
#else
#define NDYNAMIC 1 /* add one at a time on embedded */
/* set counted */
#define __sFXInit3 {.fl_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER, .counted = 1}
-static int __scounted; /* streams counted against STREAM_MAX */
-static int __stream_max;
+static int64_t __scounted; /* streams counted against STREAM_MAX */
+static int64_t __stream_max;
-#if !TARGET_OS_EMBEDDED
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
/* usual and usual_extra are data pigs. See 7929728. For embedded we should
* always allocate dynamically, and probably should for desktop too. */
/* the usual - (stdin + stdout + stderr) */
static FILE usual[FOPEN_MAX - 3];
static struct __sFILEX usual_extra[FOPEN_MAX - 3];
static struct glue uglue = { NULL, FOPEN_MAX - 3, usual };
-#endif /* !TARGET_OS_EMBEDDED */
+#endif /* !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
static struct __sFILEX __sFX[3] = {__sFXInit3, __sFXInit3, __sFXInit3};
FILE *__stdoutp = &__sF[1];
FILE *__stderrp = &__sF[2];
-#if !TARGET_OS_EMBEDDED
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
struct glue __sglue = { &uglue, 3, __sF };
static struct glue *lastglue = &uglue;
#else
pthread_once(&__sdidinit, __sinit);
if (count) {
- int32_t new = OSAtomicIncrement32(&__scounted);
+ int64_t new = OSAtomicIncrement64(&__scounted);
if (new > __stream_max) {
+ /* Greater than the saved limit, check again with getrlimit. */
if (new > (__stream_max = sysconf(_SC_STREAM_MAX))){
- OSAtomicDecrement32(&__scounted);
+ OSAtomicDecrement64(&__scounted);
errno = EMFILE;
return NULL;
}
}
+ /* Overflowing #streams beyond RLIMIT_INFINITY */
+ if (new < 0) {
+ errno = EOVERFLOW;
+ return NULL;
+ }
}
/*
* The list must be locked because a FILE may be updated.
__sfprelease(FILE *fp)
{
if (fp->_counted) {
- OSAtomicDecrement32(&__scounted);
+ OSAtomicDecrement64(&__scounted);
fp->_counted = 0;
}
void
__sinit(void)
{
-#if !TARGET_OS_EMBEDDED
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
int i;
#endif
__stream_max = sysconf(_SC_STREAM_MAX);
__scounted = 3; /* std{in,out,err} already exists */
-#if !TARGET_OS_EMBEDDED
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
/* Set _extra for the usual suspects. */
for (i = 0; i < FOPEN_MAX - 3; i++) {
usual[i]._extra = &usual_extra[i];
}
}
-#if !TARGET_IPHONE_SIMULATOR && (__i386__ || __x86_64__)
+#if TARGET_OS_OSX
/*
* Support for thread_local in C++, using existing _tlv_atexit() in libdyld
*/
+++ /dev/null
-/****************************************************************************/
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.15 2008/01/14 09:21:34 das Exp $");
-
-#include <stdlib.h>
-#include <pthread.h>
-#include <dispatch/dispatch.h>
-#include <stddef.h>
-#include <string.h>
-#include <libkern/OSAtomic.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <os/lock.h>
-#define __APPLE_API_PRIVATE
-#include <machine/cpu_capabilities.h>
-
-#ifdef I_AM_PSORT_R
-typedef int cmp_t(void *, const void *, const void *);
-#else
-typedef int cmp_t(const void *, const void *);
-#endif
-#ifdef I_AM_PSORT_B
-static inline char *med3(char *, char *, char *, cmp_t ^, void *) __attribute__((always_inline));
-#else
-static inline char *med3(char *, char *, char *, cmp_t *, void *) __attribute__((always_inline));
-#endif
-static inline void swapfunc(char *, char *, int, int) __attribute__((always_inline));
-
-#define min(a, b) (a) < (b) ? a : b
-
-#define NARGS ((PAGESIZE - offsetof(struct page, args)) / sizeof(union args))
-#define PAGESIZE 4096
-#define PARALLEL_MIN_SIZE 2000 /* determine heuristically */
-
-struct shared; /* forward reference */
-union args {
- union args *next;
- struct {
- struct shared *shared;
- void *a;
- size_t n;
- int depth_limit;
- } /* anonymous */;
-};
-
-struct page {
- struct page *next;
- union args args[0];
-};
-
-struct shared {
- char *who;
- union args *freelist;
- struct page *pagelist;
-#ifdef I_AM_PSORT_R
- void *thunk;
-#endif
-#ifdef I_AM_PSORT_B
- cmp_t ^cmp;
-#else
- cmp_t *cmp;
-#endif
- size_t es;
- size_t turnoff;
- dispatch_queue_t queue;
- dispatch_group_t group;
- os_unfair_lock sharedlock;
-};
-
-static union args *
-getargs(struct shared *shared)
-{
- union args *args;
-
- os_unfair_lock_lock(&shared->sharedlock);
- if(!shared->freelist) {
- struct page *page;
- union args *prev;
- int i;
- if((page = (struct page *)mmap(NULL, PAGESIZE, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0)) == NULL)
- return NULL;
- page->next = shared->pagelist;
- shared->pagelist = page;
- prev = NULL;
- for(args = page->args, i = NARGS; i > 0; args++, i--) {
- args->next = prev;
- prev = args;
- }
- shared->freelist = prev;
- }
- args = shared->freelist;
- shared->freelist = args->next;
- os_unfair_lock_unlock(&shared->sharedlock);
- return args;
-}
-
-static void
-returnargs(struct shared *shared, union args *args)
-{
- os_unfair_lock_lock(&shared->sharedlock);
- args->next = shared->freelist;
- shared->freelist = args;
- os_unfair_lock_unlock(&shared->sharedlock);
-}
-
-/*
- * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
- */
-#define swapcode(TYPE, parmi, parmj, n) { \
- long i = (n) / sizeof (TYPE); \
- TYPE *pi = (TYPE *) (parmi); \
- TYPE *pj = (TYPE *) (parmj); \
- do { \
- TYPE t = *pi; \
- *pi++ = *pj; \
- *pj++ = t; \
- } while (--i > 0); \
-}
-
-#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
- es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
-
-static inline void
-swapfunc(a, b, n, swaptype)
- char *a, *b;
- int n, swaptype;
-{
- if(swaptype <= 1)
- swapcode(long, a, b, n)
- else
- swapcode(char, a, b, n)
-}
-
-#define swap(a, b) \
- if (swaptype == 0) { \
- long t = *(long *)(a); \
- *(long *)(a) = *(long *)(b); \
- *(long *)(b) = t; \
- } else \
- swapfunc(a, b, es, swaptype)
-
-#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
-
-#ifdef I_AM_PSORT_R
-#define CMP(t, x, y) (cmp((t), (x), (y)))
-#else
-#define CMP(t, x, y) (cmp((x), (y)))
-#endif
-
-static inline char *
-med3(char *a, char *b, char *c,
-#ifdef I_AM_PSORT_B
-cmp_t ^cmp,
-#else
-cmp_t *cmp,
-#endif
-void *thunk
-#ifndef I_AM_PSORT_R
-__unused
-#endif
-)
-{
- return CMP(thunk, a, b) < 0 ?
- (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
- :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
-}
-
-#ifdef __LP64__
-#define DEPTH(x) (2 * (flsl((long)(x)) - 1))
-#else /* !__LP64__ */
-#define DEPTH(x) (2 * (fls((int)(x)) - 1))
-#endif /* __LP64__ */
-
-#ifdef I_AM_PSORT_R
-int __heapsort_r(void *, size_t, size_t, void *, int (*)(void *, const void *, const void *));
-#endif
-
-static void _psort_parallel(void *x);
-
-static void
-_psort(void *a, size_t n, size_t es,
-#ifdef I_AM_PSORT_R
-void *thunk,
-#else
-#define thunk NULL
-#endif
-#ifdef I_AM_PSORT_B
-cmp_t ^cmp,
-#else
-cmp_t *cmp,
-#endif
-int depth_limit, struct shared *shared)
-{
- char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
- size_t d, r;
- int cmp_result;
- int swaptype, swap_cnt;
-
-loop:
- if (depth_limit-- <= 0) {
-#ifdef I_AM_PSORT_B
- heapsort_b(a, n, es, cmp);
-#elif defined(I_AM_PSORT_R)
- __heapsort_r(a, n, es, thunk, cmp);
-#else
- heapsort(a, n, es, cmp);
-#endif
- return;
- }
- SWAPINIT(a, es);
- swap_cnt = 0;
- if (n < 7) {
- for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
- for (pl = pm;
- pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
- pl -= es)
- swap(pl, pl - es);
- return;
- }
- pm = (char *)a + (n / 2) * es;
- if (n > 7) {
- pl = a;
- pn = (char *)a + (n - 1) * es;
- if (n > 40) {
- d = (n / 8) * es;
- pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
- pm = med3(pm - d, pm, pm + d, cmp, thunk);
- pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
- }
- pm = med3(pl, pm, pn, cmp, thunk);
- }
- swap(a, pm);
- pa = pb = (char *)a + es;
-
- pc = pd = (char *)a + (n - 1) * es;
- for (;;) {
- while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
- if (cmp_result == 0) {
- swap_cnt = 1;
- swap(pa, pb);
- pa += es;
- }
- pb += es;
- }
- while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
- if (cmp_result == 0) {
- swap_cnt = 1;
- swap(pc, pd);
- pd -= es;
- }
- pc -= es;
- }
- if (pb > pc)
- break;
- swap(pb, pc);
- swap_cnt = 1;
- pb += es;
- pc -= es;
- }
-
- pn = (char *)a + n * es;
- r = min(pa - (char *)a, pb - pa);
- vecswap(a, pb - r, r);
- r = min(pd - pc, pn - pd - es);
- vecswap(pb, pn - r, r);
-
- if (swap_cnt == 0) { /* Switch to insertion sort */
- r = 1 + n / 4; /* n >= 7, so r >= 2 */
- for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
- for (pl = pm;
- pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
- pl -= es) {
- swap(pl, pl - es);
- if (++swap_cnt > r) goto nevermind;
- }
- return;
- }
-
-nevermind:
- if ((r = pb - pa) > es) {
- r /= es;
- if (shared && r > shared->turnoff) {
- union args *args = getargs(shared);
-
- if (args == NULL)
- LIBC_ABORT("%s: getargs: %s", shared->who, strerror(errno));
- args->shared = shared;
- args->a = a;
- args->n = r;
- args->depth_limit = depth_limit;
- dispatch_group_async_f(shared->group, shared->queue, args,
- _psort_parallel);
- } else {
-#ifdef I_AM_PSORT_R
- _psort(a, r, es, thunk, cmp, depth_limit, NULL);
-#else
- _psort(a, r, es, cmp, depth_limit, NULL);
-#endif
- }
- }
- if ((r = pd - pc) > es) {
- /* Iterate rather than recurse to save stack space */
- a = pn - r;
- n = r / es;
- goto loop;
- }
-/* psort(pn - r, r / es, es, cmp);*/
-}
-
-static void
-_psort_parallel(void *x)
-{
- union args *args = (union args *)x;
- struct shared *shared = args->shared;
-
- _psort(args->a, args->n, shared->es,
-#ifdef I_AM_PSORT_R
- shared->thunk,
-#endif
- shared->cmp, args->depth_limit, shared);
- returnargs(shared, args);
-}
-
-/* fast, approximate integer square root */
-static size_t
-isqrt(size_t x)
-{
- size_t s = 1L << (flsl(x) / 2);
- return (s + x / s) / 2;
-}
-
-void
-#ifdef I_AM_PSORT_R
-psort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
-#elif defined(I_AM_PSORT_B)
-psort_b(void *a, size_t n, size_t es, cmp_t ^cmp)
-#else
-psort(void *a, size_t n, size_t es, cmp_t *cmp)
-#endif
-{
- if (n >= PARALLEL_MIN_SIZE && _NumCPUs() > 1) {
- struct shared shared;
- union args *args;
-
- bzero(&shared, sizeof(shared));
- shared.sharedlock = OS_UNFAIR_LOCK_INIT;
- if ((args = getargs(&shared)) != NULL) {
- struct page *p, *pp;
-#ifdef I_AM_PSORT_R
- shared.who = "psort_r";
- shared.thunk = thunk;
-#elif defined(I_AM_PSORT_B)
- shared.who = "psort_b";
-#else
- shared.who = "psort";
-#endif
- shared.cmp = cmp;
- shared.es = es;
- shared.queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- shared.group = dispatch_group_create();
- args->a = a;
- args->n = n;
- args->depth_limit = DEPTH(n);
- args->shared = &shared;
- /*
- * The turnoff value is the size of a partition that,
- * below which, we stop doing in parallel, and just do
- * in the current thread. The value of sqrt(n) was
- * determined heuristically. There is a smaller
- * dependence on the slowness of the comparison
- * function, and there might be a dependence on the
- * number of processors, but the algorithm has not been
- * determined. Because the sensitivity to the turnoff
- * value is relatively low, we use a fast, approximate
- * integer square root routine that is good enough for
- * this purpose.
- */
- shared.turnoff = isqrt(n);
- _psort_parallel(args);
-
- /* wait for queue to drain */
- dispatch_group_wait(shared.group, DISPATCH_TIME_FOREVER);
- dispatch_release(shared.group);
- for(p = shared.pagelist; p; p = pp) {
- pp = p->next;
- munmap(p, PAGESIZE);
- }
- return;
- }
- }
- /* Just call qsort */
-#ifdef I_AM_PSORT_R
- qsort_r(a, n, es, thunk, cmp);
-#elif defined(I_AM_PSORT_B)
- qsort_b(a, n, es, cmp);
-#else
- qsort(a, n, es, cmp);
-#endif
-}
--- /dev/null
+.
\ No newline at end of file
+++ /dev/null
-/****************************************************************************/
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.15 2008/01/14 09:21:34 das Exp $");
-
-#include <stdlib.h>
-#include <pthread.h>
-#include <dispatch/dispatch.h>
-#include <stddef.h>
-#include <string.h>
-#include <libkern/OSAtomic.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <os/lock.h>
-#define __APPLE_API_PRIVATE
-#include <machine/cpu_capabilities.h>
-
-#ifdef I_AM_PSORT_R
-typedef int cmp_t(void *, const void *, const void *);
-#else
-typedef int cmp_t(const void *, const void *);
-#endif
-#ifdef I_AM_PSORT_B
-static inline char *med3(char *, char *, char *, cmp_t ^, void *) __attribute__((always_inline));
-#else
-static inline char *med3(char *, char *, char *, cmp_t *, void *) __attribute__((always_inline));
-#endif
-static inline void swapfunc(char *, char *, int, int) __attribute__((always_inline));
-
-#define min(a, b) (a) < (b) ? a : b
-
-#define NARGS ((PAGESIZE - offsetof(struct page, args)) / sizeof(union args))
-#define PAGESIZE 4096
-#define PARALLEL_MIN_SIZE 2000 /* determine heuristically */
-
-struct shared; /* forward reference */
-union args {
- union args *next;
- struct {
- struct shared *shared;
- void *a;
- size_t n;
- int depth_limit;
- } /* anonymous */;
-};
-
-struct page {
- struct page *next;
- union args args[0];
-};
-
-struct shared {
- char *who;
- union args *freelist;
- struct page *pagelist;
-#ifdef I_AM_PSORT_R
- void *thunk;
-#endif
-#ifdef I_AM_PSORT_B
- cmp_t ^cmp;
-#else
- cmp_t *cmp;
-#endif
- size_t es;
- size_t turnoff;
- dispatch_queue_t queue;
- dispatch_group_t group;
- os_unfair_lock sharedlock;
-};
-
-static union args *
-getargs(struct shared *shared)
-{
- union args *args;
-
- os_unfair_lock_lock(&shared->sharedlock);
- if(!shared->freelist) {
- struct page *page;
- union args *prev;
- int i;
- if((page = (struct page *)mmap(NULL, PAGESIZE, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0)) == NULL)
- return NULL;
- page->next = shared->pagelist;
- shared->pagelist = page;
- prev = NULL;
- for(args = page->args, i = NARGS; i > 0; args++, i--) {
- args->next = prev;
- prev = args;
- }
- shared->freelist = prev;
- }
- args = shared->freelist;
- shared->freelist = args->next;
- os_unfair_lock_unlock(&shared->sharedlock);
- return args;
-}
-
-static void
-returnargs(struct shared *shared, union args *args)
-{
- os_unfair_lock_lock(&shared->sharedlock);
- args->next = shared->freelist;
- shared->freelist = args;
- os_unfair_lock_unlock(&shared->sharedlock);
-}
-
-/*
- * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
- */
-#define swapcode(TYPE, parmi, parmj, n) { \
- long i = (n) / sizeof (TYPE); \
- TYPE *pi = (TYPE *) (parmi); \
- TYPE *pj = (TYPE *) (parmj); \
- do { \
- TYPE t = *pi; \
- *pi++ = *pj; \
- *pj++ = t; \
- } while (--i > 0); \
-}
-
-#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
- es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
-
-static inline void
-swapfunc(a, b, n, swaptype)
- char *a, *b;
- int n, swaptype;
-{
- if(swaptype <= 1)
- swapcode(long, a, b, n)
- else
- swapcode(char, a, b, n)
-}
-
-#define swap(a, b) \
- if (swaptype == 0) { \
- long t = *(long *)(a); \
- *(long *)(a) = *(long *)(b); \
- *(long *)(b) = t; \
- } else \
- swapfunc(a, b, es, swaptype)
-
-#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
-
-#ifdef I_AM_PSORT_R
-#define CMP(t, x, y) (cmp((t), (x), (y)))
-#else
-#define CMP(t, x, y) (cmp((x), (y)))
-#endif
-
-static inline char *
-med3(char *a, char *b, char *c,
-#ifdef I_AM_PSORT_B
-cmp_t ^cmp,
-#else
-cmp_t *cmp,
-#endif
-void *thunk
-#ifndef I_AM_PSORT_R
-__unused
-#endif
-)
-{
- return CMP(thunk, a, b) < 0 ?
- (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
- :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
-}
-
-#ifdef __LP64__
-#define DEPTH(x) (2 * (flsl((long)(x)) - 1))
-#else /* !__LP64__ */
-#define DEPTH(x) (2 * (fls((int)(x)) - 1))
-#endif /* __LP64__ */
-
-#ifdef I_AM_PSORT_R
-int __heapsort_r(void *, size_t, size_t, void *, int (*)(void *, const void *, const void *));
-#endif
-
-static void _psort_parallel(void *x);
-
-static void
-_psort(void *a, size_t n, size_t es,
-#ifdef I_AM_PSORT_R
-void *thunk,
-#else
-#define thunk NULL
-#endif
-#ifdef I_AM_PSORT_B
-cmp_t ^cmp,
-#else
-cmp_t *cmp,
-#endif
-int depth_limit, struct shared *shared)
-{
- char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
- size_t d, r;
- int cmp_result;
- int swaptype, swap_cnt;
-
-loop:
- if (depth_limit-- <= 0) {
-#ifdef I_AM_PSORT_B
- heapsort_b(a, n, es, cmp);
-#elif defined(I_AM_PSORT_R)
- __heapsort_r(a, n, es, thunk, cmp);
-#else
- heapsort(a, n, es, cmp);
-#endif
- return;
- }
- SWAPINIT(a, es);
- swap_cnt = 0;
- if (n < 7) {
- for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
- for (pl = pm;
- pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
- pl -= es)
- swap(pl, pl - es);
- return;
- }
- pm = (char *)a + (n / 2) * es;
- if (n > 7) {
- pl = a;
- pn = (char *)a + (n - 1) * es;
- if (n > 40) {
- d = (n / 8) * es;
- pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
- pm = med3(pm - d, pm, pm + d, cmp, thunk);
- pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
- }
- pm = med3(pl, pm, pn, cmp, thunk);
- }
- swap(a, pm);
- pa = pb = (char *)a + es;
-
- pc = pd = (char *)a + (n - 1) * es;
- for (;;) {
- while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
- if (cmp_result == 0) {
- swap_cnt = 1;
- swap(pa, pb);
- pa += es;
- }
- pb += es;
- }
- while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
- if (cmp_result == 0) {
- swap_cnt = 1;
- swap(pc, pd);
- pd -= es;
- }
- pc -= es;
- }
- if (pb > pc)
- break;
- swap(pb, pc);
- swap_cnt = 1;
- pb += es;
- pc -= es;
- }
-
- pn = (char *)a + n * es;
- r = min(pa - (char *)a, pb - pa);
- vecswap(a, pb - r, r);
- r = min(pd - pc, pn - pd - es);
- vecswap(pb, pn - r, r);
-
- if (swap_cnt == 0) { /* Switch to insertion sort */
- r = 1 + n / 4; /* n >= 7, so r >= 2 */
- for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
- for (pl = pm;
- pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
- pl -= es) {
- swap(pl, pl - es);
- if (++swap_cnt > r) goto nevermind;
- }
- return;
- }
-
-nevermind:
- if ((r = pb - pa) > es) {
- r /= es;
- if (shared && r > shared->turnoff) {
- union args *args = getargs(shared);
-
- if (args == NULL)
- LIBC_ABORT("%s: getargs: %s", shared->who, strerror(errno));
- args->shared = shared;
- args->a = a;
- args->n = r;
- args->depth_limit = depth_limit;
- dispatch_group_async_f(shared->group, shared->queue, args,
- _psort_parallel);
- } else {
-#ifdef I_AM_PSORT_R
- _psort(a, r, es, thunk, cmp, depth_limit, NULL);
-#else
- _psort(a, r, es, cmp, depth_limit, NULL);
-#endif
- }
- }
- if ((r = pd - pc) > es) {
- /* Iterate rather than recurse to save stack space */
- a = pn - r;
- n = r / es;
- goto loop;
- }
-/* psort(pn - r, r / es, es, cmp);*/
-}
-
-static void
-_psort_parallel(void *x)
-{
- union args *args = (union args *)x;
- struct shared *shared = args->shared;
-
- _psort(args->a, args->n, shared->es,
-#ifdef I_AM_PSORT_R
- shared->thunk,
-#endif
- shared->cmp, args->depth_limit, shared);
- returnargs(shared, args);
-}
-
-/* fast, approximate integer square root */
-static size_t
-isqrt(size_t x)
-{
- size_t s = 1L << (flsl(x) / 2);
- return (s + x / s) / 2;
-}
-
-void
-#ifdef I_AM_PSORT_R
-psort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
-#elif defined(I_AM_PSORT_B)
-psort_b(void *a, size_t n, size_t es, cmp_t ^cmp)
-#else
-psort(void *a, size_t n, size_t es, cmp_t *cmp)
-#endif
-{
- if (n >= PARALLEL_MIN_SIZE && _NumCPUs() > 1) {
- struct shared shared;
- union args *args;
-
- bzero(&shared, sizeof(shared));
- shared.sharedlock = OS_UNFAIR_LOCK_INIT;
- if ((args = getargs(&shared)) != NULL) {
- struct page *p, *pp;
-#ifdef I_AM_PSORT_R
- shared.who = "psort_r";
- shared.thunk = thunk;
-#elif defined(I_AM_PSORT_B)
- shared.who = "psort_b";
-#else
- shared.who = "psort";
-#endif
- shared.cmp = cmp;
- shared.es = es;
- shared.queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- shared.group = dispatch_group_create();
- args->a = a;
- args->n = n;
- args->depth_limit = DEPTH(n);
- args->shared = &shared;
- /*
- * The turnoff value is the size of a partition that,
- * below which, we stop doing in parallel, and just do
- * in the current thread. The value of sqrt(n) was
- * determined heuristically. There is a smaller
- * dependence on the slowness of the comparison
- * function, and there might be a dependence on the
- * number of processors, but the algorithm has not been
- * determined. Because the sensitivity to the turnoff
- * value is relatively low, we use a fast, approximate
- * integer square root routine that is good enough for
- * this purpose.
- */
- shared.turnoff = isqrt(n);
- _psort_parallel(args);
-
- /* wait for queue to drain */
- dispatch_group_wait(shared.group, DISPATCH_TIME_FOREVER);
- dispatch_release(shared.group);
- for(p = shared.pagelist; p; p = pp) {
- pp = p->next;
- munmap(p, PAGESIZE);
- }
- return;
- }
- }
- /* Just call qsort */
-#ifdef I_AM_PSORT_R
- qsort_r(a, n, es, thunk, cmp);
-#elif defined(I_AM_PSORT_B)
- qsort_b(a, n, es, cmp);
-#else
- qsort(a, n, es, cmp);
-#endif
-}
--- /dev/null
+.
\ No newline at end of file
.Dv _DARWIN_C_SOURCE
or
.Dv _DARWIN_BETTER_REALPATH
-before including stdio.h will cause the provided implementation of
+before including stdlib.h will cause the provided implementation of
.Fn realpath
to use F_GETPATH from
.Xr fcntl 2
--- /dev/null
+.\" Copyright (c) 2004 Ted Unangst
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $OpenBSD: strtonum.3,v 1.13 2006/04/25 05:15:42 tedu Exp $
+.\" $FreeBSD$
+.\"
+.Dd April 29, 2004
+.Dt STRTONUM 3
+.Os
+.Sh NAME
+.Nm strtonum
+.Nd "reliably convert string value to an integer"
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft long long
+.Fo strtonum
+.Fa "const char *nptr"
+.Fa "long long minval"
+.Fa "long long maxval"
+.Fa "const char **errstr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn strtonum
+function converts the string in
+.Fa nptr
+to a
+.Vt "long long"
+value.
+The
+.Fn strtonum
+function was designed to facilitate safe, robust programming
+and overcome the shortcomings of the
+.Xr atoi 3
+and
+.Xr strtol 3
+family of interfaces.
+.Pp
+The string may begin with an arbitrary amount of whitespace
+(as determined by
+.Xr isspace 3 )
+followed by a single optional
+.Ql +
+or
+.Ql -
+sign.
+.Pp
+The remainder of the string is converted to a
+.Vt "long long"
+value according to base 10.
+.Pp
+The value obtained is then checked against the provided
+.Fa minval
+and
+.Fa maxval
+bounds.
+If
+.Fa errstr
+is non-null,
+.Fn strtonum
+stores an error string in
+.Fa *errstr
+indicating the failure.
+.Sh RETURN VALUES
+The
+.Fn strtonum
+function returns the result of the conversion,
+unless the value would exceed the provided bounds or is invalid.
+On error, 0 is returned,
+.Va errno
+is set, and
+.Fa errstr
+will point to an error message.
+On success,
+.Fa *errstr
+will be set to
+.Dv NULL ;
+this fact can be used to differentiate
+a successful return of 0 from an error.
+.Sh EXAMPLES
+Using
+.Fn strtonum
+correctly is meant to be simpler than the alternative functions.
+.Bd -literal -offset indent
+int iterations;
+const char *errstr;
+
+iterations = strtonum(optarg, 1, 64, &errstr);
+if (errstr != NULL)
+ errx(1, "number of iterations is %s: %s", errstr, optarg);
+.Ed
+.Pp
+The above example will guarantee that the value of iterations is between
+1 and 64 (inclusive).
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ERANGE
+The given string was out of range.
+.It Bq Er EINVAL
+The given string did not consist solely of digit characters.
+.It Bq Er EINVAL
+The supplied
+.Fa minval
+was larger than
+.Fa maxval .
+.El
+.Pp
+If an error occurs,
+.Fa errstr
+will be set to one of the following strings:
+.Pp
+.Bl -tag -width ".Li too large" -compact
+.It Li "too large"
+The result was larger than the provided maximum value.
+.It Li "too small"
+The result was smaller than the provided minimum value.
+.It Li invalid
+The string did not consist solely of digit characters.
+.El
+.Sh SEE ALSO
+.Xr atof 3 ,
+.Xr atoi 3 ,
+.Xr atol 3 ,
+.Xr atoll 3 ,
+.Xr sscanf 3 ,
+.Xr strtod 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3
+.Sh STANDARDS
+The
+.Fn strtonum
+function is a
+.Bx
+extension.
+The existing alternatives, such as
+.Xr atoi 3
+and
+.Xr strtol 3 ,
+are either impossible or difficult to use safely.
+.Sh HISTORY
+The
+.Fn strtonum
+function first appeared in
+.Ox 3.6 .
--- /dev/null
+/*-
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ int error = 0;
+ char *ep;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval) {
+ error = INVALID;
+ } else {
+ ll = strtoll(numstr, &ep, 10);
+ if (errno == EINVAL || numstr == ep || *ep != '\0')
+ error = INVALID;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = TOOSMALL;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
*cs_precedes = lc->int_n_cs_precedes;
*sep_by_space = lc->int_n_sep_by_space;
*sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_n_sign_posn;
- *signstr = (lc->negative_sign == '\0') ? "-"
+ *signstr = (*lc->negative_sign == '\0') ? "-"
: lc->negative_sign;
} else if (flags & USE_INTL_CURRENCY) {
*cs_precedes = lc->int_p_cs_precedes;
*cs_precedes = lc->n_cs_precedes;
*sep_by_space = lc->n_sep_by_space;
*sign_posn = (flags & PARENTH_POSN) ? 0 : lc->n_sign_posn;
- *signstr = (lc->negative_sign == '\0') ? "-"
+ *signstr = (*lc->negative_sign == '\0') ? "-"
: lc->negative_sign;
} else {
*cs_precedes = lc->p_cs_precedes;
typedef struct {
int token;
int is_set;
- int null_bootstrap;
} notify_tz_t;
#define NOTIFY_TZ_NAME "com.apple.system.timezone"
}
#endif /* NOTIFY_TZ_LOG */
-static notify_tz_t gmt_notify = {-1, 0, 0};
-static notify_tz_t lcl_notify = {-1, 0, 0};
+static notify_tz_t gmt_notify = {-1, 0};
+static notify_tz_t lcl_notify = {-1, 0};
static const char notify_tz_name[] = NOTIFY_TZ_NAME;
#endif /* NOTIFY_TZ */
}
#ifdef NOTIFY_TZ
-static int
-do_null_bootstrap_check(notify_tz_t *p)
-{
- /*
- * If we're running in a null bootstrap context (e.g. the bootstrap server),
- * we will not be able to contact the notify server. In this case we want to
- * avoid opening /etc/localtime every time the process does a asctime_r(3)
- * or similar. But we have to do this once to get the right time zone.
- *
- * So first time through, we set a bit to indicate that we're in the null
- * bootstrap context. The second time through, we force the "set" bit in the
- * notify_tz_t structure to -1 and avoid the path where it can be set to
- * zero (which would trigger opening and reloading the timezone file).
- */
- if (bootstrap_port != MACH_PORT_NULL) {
- return -1;
- }
-
- if (!p->null_bootstrap) {
- p->null_bootstrap = 1;
- p->is_set = 0;
- return -1;
- }
-
- p->is_set = -1;
- return 0;
-}
-
static void
notify_check_tz(notify_tz_t *p)
{
if (p->token < 0)
return;
- if (do_null_bootstrap_check(p) == 0) {
- return;
- }
nstat = notify_check(p->token, &ncheck);
if (nstat || ncheck) {
p->is_set = 0;
unsigned int nstat;
int ncheck;
- if (do_null_bootstrap_check(p) == 0) {
+ if (bootstrap_port == MACH_PORT_NULL) {
+ /* error handling below resets is_set, we don't want that */
return;
}
(void) tzparse(gmt, sp, TRUE);
}
+/**
+ * In NULL_BOOTSTRAP environments, we can't use notifyd to learn about the changes in timezone.
+ * Instead, we look at the modified time of the TZDEFAULT symlink.
+ * As a performance optimization, we only reload the timezone data if the modified time is newer than the
+ * last time we loaded the timezone file.
+ *
+ * If the tzload fails, we need to reset the saved timestamp to force the timezone file to be reloaded next time
+ * we try to use it. This is a special case that occurs at first boot for launchd (and other early boot-tasks)
+ * rdar://60592414
+ */
+static struct timespec last_default_tzload_mtimespec = {0, 0};
+static void
+tzsetwall_check_default_file_timestamp(void)
+{
+ if (!TZDEFAULT) {
+ return;
+ }
+
+ struct stat statbuf;
+
+ if (lstat(TZDEFAULT, &statbuf) == 0) {
+ if (statbuf.st_mtimespec.tv_sec > last_default_tzload_mtimespec.tv_sec ||
+ (statbuf.st_mtimespec.tv_sec == last_default_tzload_mtimespec.tv_sec &&
+ statbuf.st_mtimespec.tv_nsec > last_default_tzload_mtimespec.tv_nsec)) {
+ /* Trigger resetting the local TZ */
+ lcl_is_set = 0;
+ }
+ last_default_tzload_mtimespec = statbuf.st_mtimespec;
+ }
+}
+
static void
tzsetwall_basic(int rdlocked)
{
#ifdef NOTIFY_TZ
- notify_check_tz(&lcl_notify);
-#else
- if (TZDEFAULT) {
- static struct timespec last_mtimespec = {0, 0};
- struct stat statbuf;
-
- if (lstat(TZDEFAULT, &statbuf) == 0) {
- if (statbuf.st_mtimespec.tv_sec > last_mtimespec.tv_sec ||
- (statbuf.st_mtimespec.tv_sec == last_mtimespec.tv_sec &&
- statbuf.st_mtimespec.tv_nsec > last_mtimespec.tv_nsec)) {
- /* Trigger resetting the local TZ */
- lcl_is_set = 0;
- }
- last_mtimespec = statbuf.st_mtimespec;
- }
+ if (bootstrap_port != MACH_PORT_NULL) {
+ notify_check_tz(&lcl_notify);
+ } else {
+ tzsetwall_check_default_file_timestamp();
}
+#else
+ tzsetwall_check_default_file_timestamp();
#endif /* NOTIFY_TZ */
+
if (!rdlocked)
_RWLOCK_RDLOCK(&lcl_rwlock);
if (lcl_is_set < 0) {
#ifdef NOTIFY_TZ
{
char fullname[FILENAME_MAX + 1];
- if (tzload((char *) NULL, lclptr, fullname, TRUE) != 0)
+ if (tzload((char *) NULL, lclptr, fullname, TRUE) != 0) {
+ // The load failed, so we need to reset the cached modified time
+ // of the timezone file
+ last_default_tzload_mtimespec = (const struct timespec){0};
+
/*
* If fullname is empty (an error occurred) then
* default to the UTC path
*/
gmtload(lclptr, *fullname ? NULL : fullname);
- notify_register_tz(fullname, &lcl_notify);
+ }
+ notify_register_tz(fullname, &lcl_notify);
}
#else /* ! NOTIFY_TZ */
if (tzload((char *) NULL, lclptr, TRUE) != 0)
* notifications.
*/
int parsedOK = FALSE;
- if (tzload(name, lclptr, fullname, TRUE) != 0)
- if (name[0] == ':' || !(parsedOK = tzparse(name, lclptr, FALSE) == 0))
+ if (tzload(name, lclptr, fullname, TRUE) != 0) {
+ if (name[0] == ':' || !(parsedOK = tzparse(name, lclptr, FALSE) == 0)) {
/*
* If fullname is empty (an error occurred) then
* default to the UTC path
*/
(void) gmtload(lclptr, *fullname ? NULL : fullname);
- notify_register_tz(parsedOK ? NULL : fullname, &lcl_notify);
+ }
+ }
+ notify_register_tz(parsedOK ? NULL : fullname, &lcl_notify);
}
#else /* ! NOTIFY_TZ */
if (tzload(name, lclptr, TRUE) != 0)
#define UPREFIX "Unknown signal"
+/*
+ * Define a buffer size big enough to describe a 64-bit signed integer
+ * converted to ASCII decimal (19 bytes), with an optional leading sign
+ * (1 byte); delimiter (": ", 2 bytes); and a trailing NUL (1 byte).
+ */
+#define TMPSIZE (19 + 1 + 2 + 1)
+#define EBUFSIZE NL_TEXTMAX * sizeof(char)
+
static once_t sig_init_once = ONCE_INITIALIZER;
static thread_key_t sig_key;
static int sig_keycreated = 0;
!sig_keycreated)
goto thr_err;
if ((ebuf = thr_getspecific(sig_key)) == NULL) {
- if ((ebuf = malloc(NL_TEXTMAX * sizeof(char))) == NULL)
+ if ((ebuf = malloc(EBUFSIZE)) == NULL)
goto thr_err;
if (thr_setspecific(sig_key, ebuf) != 0) {
free(ebuf);
return (ebuf);
}
-/* XXX: negative 'num' ? (REGR) */
-char *
-strsignal(int num)
+int
+strsignal_r(int num, char *strsignalbuf, size_t buflen)
{
- char *ebuf;
- char tmp[20];
+ int retval = 0;
+ char tmp[TMPSIZE] = { 0 };
size_t n;
int signum;
char *t, *p;
-#if defined(NLS)
- int saved_errno = errno;
- nl_catd catd;
- catd = catopen("libc", NL_CAT_LOCALE);
-#endif
+ signum = num;
+ if (num < 0) {
+ signum = -signum;
+ }
- ebuf = sig_tlsalloc();
- if(ebuf == NULL) {
- errno = ENOMEM;
- return NULL;
+ t = tmp;
+ do {
+ *t++ = "0123456789"[signum % 10];
+ } while (signum /= 10);
+ if (num < 0) {
+ *t++ = '-';
}
+ int suffixlen = strlen(tmp) + 2;
if (num > 0 && num < NSIG) {
- n = strlcpy(ebuf,
-#if defined(NLS)
- catgets(catd, 2, num, sys_siglist[num]),
-#else
+ n = strlcpy(strsignalbuf,
sys_siglist[num],
-#endif
- NL_TEXTMAX * sizeof(char));
+ buflen);
+ if (n >= (buflen - suffixlen)) {
+ retval = ERANGE;
+ }
} else {
- n = strlcpy(ebuf,
-#if defined(NLS)
- catgets(catd, 2, 0xffff, UPREFIX),
-#else
+ n = strlcpy(strsignalbuf,
UPREFIX,
-#endif
- NL_TEXTMAX * sizeof(char));
+ buflen);
+ retval = EINVAL;
}
- signum = num;
- if (num < 0)
- signum = -signum;
+ if (n < (buflen - suffixlen)) {
+ p = (strsignalbuf + n);
+ *p++ = ':';
+ *p++ = ' ';
- t = tmp;
- do {
- *t++ = "0123456789"[signum % 10];
- } while (signum /= 10);
- if (num < 0)
- *t++ = '-';
+ for (;;) {
+ *p++ = *--t;
+ if (t <= tmp)
+ break;
+ }
+ *p = '\0';
+ }
+
+ return retval;
+}
- p = (ebuf + n);
- *p++ = ':';
- *p++ = ' ';
+/* XXX: negative 'num' ? (REGR) */
+char *
+strsignal(int num)
+{
+ char *ebuf;
+
+ ebuf = sig_tlsalloc();
+ if (ebuf == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
- for (;;) {
- *p++ = *--t;
- if (t <= tmp)
- break;
+ if (strsignal_r(num, ebuf, EBUFSIZE)) {
+ errno = EINVAL;
}
- *p = '\0';
-#if defined(NLS)
- catclose(catd);
- errno = saved_errno;
-#endif
return (ebuf);
}
extern void __chk_init(void);
extern void __xlocale_init(void);
extern void __guard_setup(const char *apple[]);
+extern void _subsystem_init(const char *apple[]);
void
_libc_initializer(const struct _libc_functions *funcs,
__chk_init();
__xlocale_init();
__guard_setup(apple);
+ _subsystem_init(apple);
}
PROJECT := Libc
TEST_DIR := tests/
-CUSTOM_TARGETS += osvariantutil
+CUSTOM_TARGETS += osvariantutil subsystem_test_helper
ifeq ($(DEVELOPER_DIR),)
DEVELOPER_DIR := $(shell xcode-select -p)
ifneq ($(PLATFORM),MacOSX)
EXCLUDED_SOURCES += locale.c
+EXCLUDED_SOURCES += os_boot_mode.c
endif
FRAMEWORK_CFLAGS := $(patsubst %,-iframework %,$(SYSTEM_FRAMEWORK_SEARCH_PATHS))
-Wno-partial-availability -Wno-used-but-marked-unused \
-Wno-reserved-id-macro -fmacro-backtrace-limit=0 \
-Wno-c++98-compat -Wno-extra-semi -Wno-language-extension-token
-OTHER_CFLAGS := -DDARWINTEST --std=gnu11 $(FRAMEWORK_CFLAGS) $(WARNING_CFLAGS) -I$(SDK_SYSTEM_FRAMEWORK_HEADERS)
+OTHER_CFLAGS := -DDARWINTEST --std=gnu11 $(FRAMEWORK_CFLAGS) $(WARNING_CFLAGS) -I$(SDK_SYSTEM_FRAMEWORK_HEADERS) -L/usr/lib/system -lsystem_collections
DT_LDFLAGS += -ldarwintest_utils
-ASAN_DYLIB_PATH := /usr/local/lib/sanitizers/
+ASAN_DYLIB_PATH := /usr/appleinternal/lib/sanitizers/
+
+OTHER_LDFLAGS := -umbrella System -L/usr/lib/system -lsystem_collections
nxheap: OTHER_CFLAGS += -Wno-cast-align
strlcat: OTHER_CFLAGS += -Wno-pointer-arith
mkdir -p $(OSVARIANTUTIL_INSTALLDIR)
cp $(SYMROOT)/osvariantutil $(OSVARIANTUTIL_INSTALLDIR)/
ifeq ($(DWARF_DSYM_FILE_SHOULD_ACCOMPANY_PRODUCT),YES)
- cp $(SYMROOT)/osvariantutil.dSYM $(OSVARIANTUTIL_INSTALLDIR)/
+ cp -R $(SYMROOT)/osvariantutil.dSYM $(OSVARIANTUTIL_INSTALLDIR)/
+endif
+
+subsystem_test: subsystem_test.c subsystem_test-entitlements.plist
+subsystem_test: CODE_SIGN_ENTITLEMENTS=subsystem_test-entitlements.plist
+
+install-subsystem_test_helper: subsystem_test_helper
+ mkdir -p $(INSTALLDIR)
+ cp $(SYMROOT)/subsystem_test_helper $(INSTALLDIR)/
+ifeq ($(DWARF_DSYM_FILE_SHOULD_ACCOMPANY_PRODUCT),YES)
+ cp -R $(SYMROOT)/subsystem_test_helper.dSYM $(INSTALLDIR)/
endif
+
--- /dev/null
+/*-+ Hello! */
--- /dev/null
+#include <TargetConditionals.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <xlocale.h>
+
+#include <darwintest.h>
+
+void __collate_lookup_l(const __darwin_wchar_t *, int *, int *, int *,
+ locale_t);
+void __collate_lookup(const unsigned char *, int *, int *, int *);
+
+#define CHARS_WITHOUT_ENTRIES "\xdf"
+
+/*
+ * in C or POSIX locales
+ * __collate_lookup("", ... ) -> len: 0 prim: 0 sec: 0
+ * __collate_lookup("a", ... ) -> len: 1 prim: (int)'a' sec: 0
+ * __collate_lookup("ab", ... ) -> len: 1 prim: (int)'a' sec: 0
+ *
+ * in a Latin-1 locale (de_DE.ISO8859-1)
+ * __collate_lookup("", ... ) -> len: 0 prim: 0 sec: 0
+ * __collate_lookup("a", ... ) -> len: 1 prim: > 0 sec: > 0
+ * __collate_lookup("ab", ... ) -> len: 1 prim: > 0 sec: > 0
+ * # a character not in the table - lookup failure
+ * __collate_lookup("\xdf", ... ) -> len: 0 prim: -1 sec: -1
+ *
+ * in a UTF-8 locale (de_DE.UTF-8)
+ * __collate_lookup("", ... ) -> len: 0 prim: 0 sec: 0
+ * __collate_lookup("a", ... ) -> len: 1 prim: > 0 sec: > 0
+ * __collate_lookup("ab", ... ) -> len: 1 prim: > 0 sec: > 0
+ * # An invalid multi-byte sequence
+ * __collate_lookup("\xe4", ... ) -> len: 1 prim: (int)'\xe4' sec: 0
+ * # valid multi-byte sequence
+ * __collate_lookup("\xc3\xa4", ... ) -> len: 2 prim: > 0 sec: > 0
+ */
+T_DECL(collate_lookup, "Test __collate_lookup() behavior") {
+ unsigned char c;
+ unsigned char str[16];
+ int len, prim, sec, prim2, sec2;
+ char *result;
+
+ /* ------------------------- C Locale ------------------------- */
+ /* In the C locale primary weights should equal the int value of the
+ * character*/
+ result = setlocale(LC_ALL, "C");
+ T_ASSERT_NOTNULL(result, "changed to C locale");
+
+ __collate_lookup("", &len, &prim, &sec);
+ T_ASSERT_EQ_INT(len, 0, "No characters read");
+ T_EXPECT_EQ_INT(prim, 0, "No primary weight");
+ T_EXPECT_EQ_INT(sec, 0, "No secondary weight");
+
+ str[1] = 'X';
+ str[2] = '\0';
+ for (c = 1; c < UCHAR_MAX; c++) {
+ len = 1;
+ str[0] = c;
+ __collate_lookup(str, &len, &prim, &sec);
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+ T_EXPECT_EQ_INT(prim, (int)c, "Primary weight returned is the value of c");
+ T_EXPECT_EQ_INT(sec, 0, "Secondary weight returned is 0");
+ }
+
+#if TARGET_OS_OSX
+ /* ------------------------- German Latin-1 Locale ----------------------- */
+ result = setlocale(LC_ALL, "de_DE.ISO8859-1");
+ T_ASSERT_NOTNULL(result, "changed to german Latin-1 locale");
+
+ __collate_lookup("", &len, &prim, &sec);
+ T_ASSERT_EQ_INT(len, 0, "No characters read");
+ T_EXPECT_EQ_INT(prim, 0, "No primary weight");
+ T_EXPECT_EQ_INT(sec, 0, "No secondary weight");
+
+ str[1] = 'X';
+ str[2] = '\0';
+ for (c = 1; c < UCHAR_MAX; c++) {
+ len = 1;
+ str[0] = c;
+ __collate_lookup(str, &len, &prim, &sec);
+ T_ASSERT_EQ_INT(len, (c == '\0' ? 0 : 1), "Only read one character");
+ str[1] = '\0';
+ if (strstr(CHARS_WITHOUT_ENTRIES, str)) {
+ T_EXPECT_EQ(prim, -1, "0x%x is not present in the table", c);
+ T_EXPECT_EQ(sec, -1, "0x%x is not present in the table", c);
+ } else {
+ T_EXPECT_GT(prim, 0, "0x%x Has primary weight", c);
+ T_EXPECT_GT(sec, 0, "0x%x Has secondary weight", c);
+ }
+ }
+
+ str[0] = 'a';
+ __collate_lookup(str, &len, &prim, &sec);
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+
+ /* a with dieresis in Latin-1 locales */
+ str[0] = (unsigned char)'\xe4';
+ __collate_lookup(str, &len, &prim2, &sec2);
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+ T_EXPECT_EQ(prim, prim2, "Same primary weight");
+ T_EXPECT_LT(sec, sec2, "Different secondary weight");
+
+ /* ------------------------- German UTF-8 Locale ------------------------- */
+ result = setlocale(LC_ALL, "de_DE.UTF-8");
+ T_ASSERT_NOTNULL(result, "changed to german UTF-8 locale");
+
+ __collate_lookup("", &len, &prim, &sec);
+ T_ASSERT_EQ_INT(len, 0, "No characters read");
+ T_EXPECT_EQ_INT(prim, 0, "No primary weight");
+ T_EXPECT_EQ_INT(sec, 0, "No secondary weight");
+
+ str[1] = 'X';
+ str[2] = '\0';
+ for (c = 1; c < UCHAR_MAX; c++) {
+ len = 2; /* Tell it that this string is longer */
+ str[0] = c;
+ __collate_lookup(str, &len, &prim, &sec);
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+ if (strstr(CHARS_WITHOUT_ENTRIES, (const char *)str)) {
+ T_EXPECT_EQ(prim, -1, "0x%x is not present in the table", c);
+ T_EXPECT_GT(sec, -1, "0x%x is not present in the table", c);
+ } else {
+ T_EXPECT_GT(prim, 0, "0x%x Has primary weight", c);
+ /* weight will be 0 for sequences that result in mb failure */
+ if (c < 128) {
+ /* So only test secondary weights for the ASCII characters */
+ T_EXPECT_GT(sec, 0, "0x%x Has secondary weight", c);
+ }
+ }
+ }
+
+ str[0] = 'a';
+ __collate_lookup(str, &len, &prim, &sec);
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+
+ /* a with dieresis in Latin-1 locales */
+ /* this character is invalid in a UTF-8 locale */
+ str[0] = (unsigned char)'\xe4';
+ errno = 0;
+ __collate_lookup(str, &len, &prim2, &sec2);
+ T_EXPECT_EQ_INT(errno, EILSEQ, "errno indicates invalid character");
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+ T_EXPECT_EQ(prim2, (unsigned int)L'\xe4',
+ "Invalid character - Primary weight equal to value (228)");
+ T_EXPECT_EQ(sec2, 0, "Invalid character - No secondary weight");
+
+ T_EXPECT_NE(prim, prim2, "Different primary weight");
+ T_EXPECT_NE(sec, sec2, "Different secondary weight");
+
+ /* Test Multibyte lookup */
+ str[0] = (unsigned char)'\xc3';
+ str[1] = (unsigned char)'\xa4';
+ str[2] = (unsigned char)'X';
+ str[3] = (unsigned char)'\0';
+ len = 3;
+ __collate_lookup(str, &len, &prim2, &sec2);
+ T_EXPECTFAIL_WITH_REASON(
+ "__collate_lookup doesn't actually tell you how many bytes were used");
+ T_ASSERT_EQ_INT(len, 2, "Only read 2 characters");
+ T_EXPECT_EQ(prim, prim2, "Same primary weight");
+ T_EXPECT_LT(sec, sec2, "Different secondary weight");
+#endif
+}
+
+/*
+ * Tests for the __collate_lookup_l() which is used to lookup weights of wide
+ * characters
+ */
+T_DECL(collate_lookup_l, "Test __collate_lookup_l() behavior") {
+ wchar_t wc;
+ wchar_t wcs[16];
+ char str[16] = {0};
+ int len, prim, sec, prim2, sec2;
+ char *result;
+
+ /* ------------------------- C Locale ------------------------- */
+ /* In the C locale primary weights should equal the int value of the
+ * character*/
+ result = setlocale(LC_ALL, "C");
+ T_ASSERT_NOTNULL(result, "changed to C locale");
+
+ __collate_lookup_l(L"", &len, &prim, &sec, LC_GLOBAL_LOCALE);
+ T_ASSERT_EQ_INT(len, 0, "No characters read");
+ T_EXPECT_EQ_INT(prim, 0, "No primary weight");
+ T_EXPECT_EQ_INT(sec, 0, "No secondary weight");
+
+ wcs[1] = L'X';
+ wcs[2] = L'\0';
+ for (wc = 1; wc < UCHAR_MAX; wc++) {
+ len = 1;
+ wcs[0] = wc;
+ errno = 0;
+ __collate_lookup_l(wcs, &len, &prim, &sec, LC_GLOBAL_LOCALE);
+ T_ASSERT_EQ_INT(errno, 0, "No error occurred");
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+ T_EXPECT_EQ_INT(prim, (int)wc,
+ "Primary weight returned is the value of wc");
+ T_EXPECT_EQ_INT(sec, 0, "Secondary weight returned is 0");
+ }
+
+#if TARGET_OS_OSX
+ /* ------------------------- German Latin-1 Locale -------------------------
+ */
+ result = setlocale(LC_ALL, "de_DE.ISO8859-1");
+ T_ASSERT_NOTNULL(result, "changed to german Latin-1 locale");
+
+ wcs[1] = L'X';
+ wcs[2] = L'\0';
+ for (wc = 1; wc < UCHAR_MAX; wc++) {
+ len = 1;
+ wcs[0] = wc;
+ str[0] = wc & 0xFF;
+ __collate_lookup_l(wcs, &len, &prim, &sec, LC_GLOBAL_LOCALE);
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+ if (strstr(CHARS_WITHOUT_ENTRIES, str)) {
+ T_EXPECT_EQ(prim, -1, "0x%x is not present in the table", wc);
+ T_EXPECT_EQ(sec, -1, "0x%x is not present in the table", wc);
+ } else {
+ T_EXPECT_GT(prim, 0, "Wide char 0x%x Has primary weight", wc);
+ T_EXPECT_GT(sec, 0, "Wide char 0x%x Has secondary weight", wc);
+ }
+ }
+
+ wcs[0] = L'a';
+ __collate_lookup_l(wcs, &len, &prim, &sec, LC_GLOBAL_LOCALE);
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+
+ /* a with dieresis in Latin-1 locales */
+ wcs[0] = L'\xe4';
+ __collate_lookup_l(wcs, &len, &prim2, &sec2, LC_GLOBAL_LOCALE);
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+ T_EXPECT_EQ(prim, prim2, "Same primary weight");
+ T_EXPECT_LT(sec, sec2, "Different secondary weight");
+
+ /* ------------------------- German UTF-8 Locale ------------------------- */
+ result = setlocale(LC_ALL, "de_DE.UTF-8");
+ T_ASSERT_NOTNULL(result, "changed to german UTF-8 locale");
+
+ __collate_lookup_l(L"", &len, &prim, &sec, LC_GLOBAL_LOCALE);
+ T_ASSERT_EQ_INT(len, 0, "No characters read");
+ T_EXPECT_EQ_INT(prim, 0, "No primary weight");
+ T_EXPECT_EQ_INT(sec, 0, "No secondary weight");
+
+ for (wc = 1; wc < UCHAR_MAX; wc++) {
+ len = 1;
+ wcs[0] = wc;
+ str[0] = wc & 0xFF;
+ __collate_lookup_l(wcs, &len, &prim, &sec, LC_GLOBAL_LOCALE);
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+ if (strstr(CHARS_WITHOUT_ENTRIES, str)) {
+ T_EXPECT_EQ(prim, -1, "0x%x is not present in the table", wc);
+ T_EXPECT_EQ(sec, -1, "0x%x is not present in the table", wc);
+ } else {
+ T_EXPECT_GT(prim, 0, "Wide char 0x%x Has primary weight", wc);
+ T_EXPECT_GT(sec, 0, "Wide char 0x%x Has secondary weight", wc);
+ }
+ }
+
+ /* Test that a lookup of 'a' and '\xe4' returns the same primary weight */
+ wcs[0] = L'a';
+ wcs[1] = L'\0';
+ __collate_lookup_l(wcs, &len, &prim, &sec, LC_GLOBAL_LOCALE);
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+ T_EXPECT_GT(prim, 0, "Wide char 0x%x Has primary weight", wc);
+ T_EXPECT_GT(sec, 0, "Wide char 0x%x Has secondary weight", wc);
+
+ wcs[0] = L'\xe4';
+ wcs[1] = L'\0';
+ errno = 0;
+ __collate_lookup_l(wcs, &len, &prim2, &sec2, LC_GLOBAL_LOCALE);
+ T_EXPECT_EQ_INT(errno, 0, "errno was not set");
+ T_ASSERT_EQ_INT(len, 1, "Only read one character");
+ T_EXPECT_GT(prim2, 0, "Wide char 0x%x Has primary weight", wc);
+ T_EXPECT_GT(sec2, 0, "Wide char 0x%x Has secondary weight", wc);
+
+ T_EXPECT_EQ(prim, prim2, "Primary weight equal");
+ T_EXPECT_NE(sec, sec2, "Different secondary weight");
+#endif
+}
--- /dev/null
+/*
+* Copyright (c) 2020 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 <os/collections.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <darwintest.h>
+
+
+T_DECL(map_basic_64, "Make sure 64 bit map basics work",
+ T_META("owner", "Core Darwin Daemons & Tools"))
+{
+ os_map_64_t basic_64_map;
+ __block bool got_cafebabe = false;
+ __block bool got_deadbeaf = false;
+ uint64_t value;
+
+ T_LOG("Start");
+
+ // *** BASIC 64 bit key testing ***
+
+ os_map_init(&basic_64_map, NULL);
+
+ T_ASSERT_EQ(os_map_count(&basic_64_map), 0, "Expect map to be empty");
+
+ os_map_insert(&basic_64_map, 0xCAFECAFE, (void *)0xCAFEBABE);
+ os_map_insert(&basic_64_map, 0xDEADDEAD, (void *)0xDEADBEEF);
+
+ T_ASSERT_EQ(os_map_count(&basic_64_map), 2,
+ "Expect map to have 2 entries");
+
+ os_map_foreach(&basic_64_map, ^bool (uint64_t key, void *value){
+ T_LOG("Foreach called for 0x%llx, 0x%llx",
+ (unsigned long long)key, (unsigned long long)value);
+ if (key == 0xCAFECAFE) {
+ T_ASSERT_EQ(value, (void *)0xCAFEBABE,
+ "Callback expect 0xCAFEBABE");
+ got_cafebabe = true;
+ } else if (key == 0xDEADDEAD) {
+ T_ASSERT_EQ(value, (void *)0xDEADBEEF,
+ "Callback expec 0xDEADBEEF");
+ got_deadbeaf = true;
+ } else {
+ T_FAIL("Got unexpected callback 0x%llx, 0x%llx",
+ (unsigned long long)key,
+ (unsigned long long)value);
+ }
+ return true;
+ });
+
+ if (!got_cafebabe || !got_deadbeaf) {
+ T_FAIL("Failed to get callback");
+ }
+
+ value = (uint64_t)os_map_find(&basic_64_map, 0xDEADDEAD);
+ T_ASSERT_EQ(value, (uint64_t)0xDEADBEEF, "Find 1");
+
+ value = (uint64_t)os_map_find(&basic_64_map, 0xCAFECAFE);
+ T_ASSERT_EQ(value, (uint64_t)0xCAFEBABE, "Find 2");
+
+ value = (uint64_t)os_map_find(&basic_64_map, 0xFF00F0F0);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "Find 3");
+
+
+ os_map_delete(&basic_64_map, 0xDEADDEAD);
+
+ T_ASSERT_EQ(os_map_count(&basic_64_map), 1,
+ "Expect map to have 1 entries");
+
+ value = (uint64_t)os_map_find(&basic_64_map, 0xDEADDEAD);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 1");
+
+ value = (uint64_t)os_map_find(&basic_64_map, 0xCAFECAFE);
+ T_ASSERT_EQ(value, (uint64_t)0xCAFEBABE, "After-delete find 2");
+
+ os_map_delete(&basic_64_map, 0xCAFECAFE);
+
+ T_ASSERT_EQ(os_map_count(&basic_64_map), 0,
+ "Expect map to be empty");
+
+ value = (uint64_t)os_map_find(&basic_64_map, 0xDEADDEAD);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 3");
+
+ value = (uint64_t)os_map_find(&basic_64_map, 0xCAFECAFE);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete find 4");
+
+ os_map_destroy(&basic_64_map);
+}
+
+T_DECL(map_basic_32, "Make sure 32 bit map basics work",
+ T_META("owner", "Core Darwin Daemons & Tools"))
+{
+ os_map_32_t basic_32_map;
+ __block bool got_cafebabe = false;
+ __block bool got_deadbeaf = false;
+ uint64_t value;
+
+ T_LOG("Start");
+
+ os_map_init(&basic_32_map, NULL);
+
+ T_ASSERT_EQ(os_map_count(&basic_32_map), 0, "Expect map to be empty");
+
+ os_map_insert(&basic_32_map, 0xCAFECAFE, (void *)0xCAFEBABE);
+ os_map_insert(&basic_32_map, 0xDEADDEAD, (void *)0xDEADBEEF);
+
+ T_ASSERT_EQ(os_map_count(&basic_32_map), 2,
+ "Expect map to have 2 entries");
+
+ os_map_foreach(&basic_32_map, ^bool (uint32_t key, void *value){
+ T_LOG("Foreach called for 0x%llx, 0x%llx",
+ (unsigned long long)key, (unsigned long long)value);
+ if (key == 0xCAFECAFE) {
+ T_ASSERT_EQ(value, (void *)0xCAFEBABE,
+ "Callback expect 0xCAFEBABE");
+ got_cafebabe = true;
+ } else if (key == 0xDEADDEAD) {
+ T_ASSERT_EQ(value, (void *)0xDEADBEEF,
+ "Callback expec 0xDEADBEEF");
+ got_deadbeaf = true;
+ } else {
+ T_FAIL("Got unexpected callback 0x%llx, 0x%llx",
+ (unsigned long long)key,
+ (unsigned long long)value);
+ }
+ return true;
+ });
+
+ if (!got_cafebabe || !got_deadbeaf) {
+ T_FAIL("Failed to get callback");
+ }
+
+ value = (uint64_t)os_map_find(&basic_32_map, 0xDEADDEAD);
+ T_ASSERT_EQ(value, (uint64_t)0xDEADBEEF, "Find 1");
+
+ value = (uint64_t)os_map_find(&basic_32_map, 0xCAFECAFE);
+ T_ASSERT_EQ(value, (uint64_t)0xCAFEBABE, "Find 2");
+
+ value = (uint64_t)os_map_find(&basic_32_map, 0xFF00F0F0);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "Find 3");
+
+ os_map_delete(&basic_32_map, 0xDEADDEAD);
+
+ T_ASSERT_EQ(os_map_count(&basic_32_map), 1,
+ "Expect map to have 1 entries");
+
+ value = (uint64_t)os_map_find(&basic_32_map, 0xDEADDEAD);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 1");
+
+ value = (uint64_t)os_map_find(&basic_32_map, 0xCAFECAFE);
+ T_ASSERT_EQ(value, (uint64_t)0xCAFEBABE, "After-delete find 2");
+
+ os_map_delete(&basic_32_map, 0xCAFECAFE);
+
+ T_ASSERT_EQ(os_map_count(&basic_32_map), 0, "Expect map to be empty");
+
+ value = (uint64_t)os_map_find(&basic_32_map, 0xDEADDEAD);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 3");
+
+ value = (uint64_t)os_map_find(&basic_32_map, 0xCAFECAFE);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete find 4");
+
+ os_map_destroy(&basic_32_map);
+}
+
+
+T_DECL(map_basic_string, "Make sure string map basics work",
+ T_META("owner", "Core Darwin Daemons & Tools"))
+{
+ os_map_str_t basic_string_map;
+ __block bool got_cafebabe = false;
+ __block bool got_deadbeaf = false;
+ uint64_t value;
+
+ T_LOG("Start");
+
+ os_map_init(&basic_string_map, NULL);
+
+ T_ASSERT_EQ(os_map_count(&basic_string_map), 0,
+ "Expect map to be empty");
+
+ os_map_insert(&basic_string_map, "0xCAFECAFE", (void *)0xCAFEBABE);
+ os_map_insert(&basic_string_map, "0xDEADDEAD", (void *)0xDEADBEEF);
+
+ T_ASSERT_EQ(os_map_count(&basic_string_map), 2,
+ "Expect map to have 2 entries");
+
+ os_map_foreach(&basic_string_map, ^bool (const char *key, void *value){
+ T_LOG("Foreach called for 0x%llx, 0x%llx",
+ (unsigned long long)key, (unsigned long long)value);
+ if (strcmp("0xCAFECAFE", key) == 0) {
+ T_ASSERT_EQ(value, (void *)0xCAFEBABE,
+ "Callback expect 0xCAFEBABE");
+ got_cafebabe = true;
+ } else if (strcmp("0xDEADDEAD", key) == 0) {
+ T_ASSERT_EQ(value, (void *)0xDEADBEEF,
+ "Callback expec 0xDEADBEEF");
+ got_deadbeaf = true;
+ } else {
+ T_FAIL("Got unexpected callback 0x%llx, 0x%llx",
+ (unsigned long long)key,
+ (unsigned long long)value);
+ }
+ return true;
+ });
+
+ if (!got_cafebabe || !got_deadbeaf) {
+ T_FAIL("Failed to get callback");
+ }
+
+ value = (uint64_t)os_map_find(&basic_string_map, "0xDEADDEAD");
+ T_ASSERT_EQ(value, (uint64_t)0xDEADBEEF, "Find 1");
+
+ value = (uint64_t)os_map_find(&basic_string_map, "0xCAFECAFE");
+ T_ASSERT_EQ(value, (uint64_t)0xCAFEBABE, "Find 2");
+
+ value = (uint64_t)os_map_find(&basic_string_map, "0xFF00F0F0");
+ T_ASSERT_EQ(value, (uint64_t)0x0, "Find 3");
+
+
+ os_map_delete(&basic_string_map, "0xDEADDEAD");
+
+ T_ASSERT_EQ(os_map_count(&basic_string_map), 1,
+ "Expect map to have 1 entries");
+
+ value = (uint64_t)os_map_find(&basic_string_map, "0xDEADDEAD");
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 1");
+
+ value = (uint64_t)os_map_find(&basic_string_map, "0xCAFECAFE");
+ T_ASSERT_EQ(value, (uint64_t)0xCAFEBABE, "After-delete find 2");
+
+ os_map_delete(&basic_string_map, "0xCAFECAFE");
+
+ T_ASSERT_EQ(os_map_count(&basic_string_map), 0,
+ "Expect map to be empty");
+
+ value = (uint64_t)os_map_find(&basic_string_map, "0xDEADDEAD");
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 3");
+
+ value = (uint64_t)os_map_find(&basic_string_map, "0xCAFECAFE");
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete find 4");
+
+ os_map_destroy(&basic_string_map);
+}
+
+T_DECL(map_entry_string, "Make sure string entry fetching works",
+ T_META("owner", "Core Darwin Daemons & Tools"))
+{
+
+ os_map_str_t basic_string_map;
+
+ T_LOG("Start");
+
+ os_map_init(&basic_string_map, NULL);
+
+ os_map_insert(&basic_string_map, "CAFE", (void *)0xCAFEBABE);
+
+ // Extra steps are taken to make sure the lookup strings aren't compiled
+ // to the same pointer.
+ volatile char lookup_string_1[5];
+ sprintf(lookup_string_1, "CAFE");
+ volatile char lookup_string_2[5];
+ sprintf(lookup_string_2, "CAFE");
+
+ T_ASSERT_EQ(strcmp(&lookup_string_1, "CAFE"), 0,
+ "Expect lookup strings to be CAFE");
+ T_ASSERT_EQ(strcmp(&lookup_string_2, "CAFE"), 0,
+ "Expect lookup strings to be CAFE");
+ T_ASSERT_NE(&lookup_string_1, &lookup_string_2,
+ "Expect lookup strings to be different");
+
+ const char *entry_string_1 = os_map_entry(&basic_string_map,
+ &lookup_string_1);
+
+ T_ASSERT_NOTNULL(entry_string_1, "Expect entry strings to be nonnull");
+ T_ASSERT_EQ(strcmp(entry_string_1, "CAFE"), 0,
+ "Expect entry strings to be CAFE");
+
+ const char *entry_string_2 = os_map_entry(&basic_string_map,
+ &lookup_string_2);
+
+ T_ASSERT_NE(entry_string_2, NULL, "Expect entry strings to be nonnull");
+ T_ASSERT_EQ(strcmp(entry_string_2, "CAFE"), 0,
+ "Expect entry strings to be CAFE");
+
+ T_ASSERT_EQ(entry_string_1, entry_string_2,
+ "Expect entry strings to be literally equal");
+
+ os_map_destroy(&basic_string_map);
+}
+
+T_DECL(map_basic_128, "Make sure 64 bit map basics work",
+ T_META("owner", "Core Darwin Daemons & Tools"))
+{
+ os_map_128_t basic_128_map;
+ __block bool got_cafebabe = false;
+ __block bool got_deadbeaf = false;
+ uint64_t value;
+
+ T_LOG("Start");
+
+ // *** BASIC 64 bit key testing ***
+
+ os_map_init(&basic_128_map, NULL);
+
+ T_ASSERT_EQ(os_map_count(&basic_128_map), 0, "Expect map to be empty");
+
+ os_map_128_key_t key;
+
+ key.x[0] = 0xCAFECAFE;
+ key.x[1] = 0xBABEBABE;
+ os_map_insert(&basic_128_map, key, (void *)0xCAFEBABE);
+
+ key.x[0] = 0xDEADDEAD;
+ key.x[1] = 0xBEEFBEEF;
+ os_map_insert(&basic_128_map, key, (void *)0xDEADBEEF);
+
+ T_ASSERT_EQ(os_map_count(&basic_128_map), 2, "Expect map to have 2 entries");
+
+ os_map_foreach(&basic_128_map, ^bool (os_map_128_key_t key, void *value){
+ T_LOG("Foreach called for 0x%llx:0x%llx, 0x%llx",
+ (unsigned long long)key.x[0], (unsigned long long)key.x[1],
+ (unsigned long long)value);
+ if (key.x[0] == 0xCAFECAFE && key.x[1] == 0xBABEBABE) {
+ T_ASSERT_EQ(value, (void *)0xCAFEBABE,
+ "Callback expect 0xCAFEBABE");
+ got_cafebabe = true;
+ } else if (key.x[0] == 0xDEADDEAD && key.x[1] == 0xBEEFBEEF) {
+ T_ASSERT_EQ(value, (void *)0xDEADBEEF, "Callback expec 0xDEADBEEF");
+ got_deadbeaf = true;
+ } else {
+ T_FAIL("Got unexpected callback 0x%llx:0x%llx, 0x%llx",
+ (unsigned long long)key.x[0], (unsigned long long)key.x[1],
+ (unsigned long long)value);
+ }
+ return true;
+ });
+
+ if (!got_cafebabe || !got_deadbeaf) {
+ T_FAIL("Failed to get callback");
+ }
+
+ key.x[0] = 0xCAFECAFE;
+ key.x[1] = 0xBABEBABE;
+ value = (uint64_t)os_map_find(&basic_128_map, key);
+ T_ASSERT_EQ(value, (uint64_t)0xCAFEBABE, "Find 1");
+
+ key.x[0] = 0xDEADDEAD;
+ key.x[1] = 0xBEEFBEEF;
+ value = (uint64_t)os_map_find(&basic_128_map, key);
+ T_ASSERT_EQ(value, (uint64_t)0xDEADBEEF, "Find 2");
+
+ key.x[0] = 0xFF00F0F0;
+ key.x[1] = 0xFF00F0F0;
+ value = (uint64_t)os_map_find(&basic_128_map, key);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "Find 3");
+
+ key.x[0] = 0xFF00F0F0;
+ key.x[1] = 0xBABEBABE;
+ value = (uint64_t)os_map_find(&basic_128_map, key);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "Find 4");
+
+ key.x[0] = 0xCAFECAFE;
+ key.x[1] = 0xFF00F0F0;
+ value = (uint64_t)os_map_find(&basic_128_map, key);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "Find 5");
+
+ key.x[0] = 0xDEADDEAD;
+ key.x[1] = 0xBEEFBEEF;
+ os_map_delete(&basic_128_map, key);
+
+ T_ASSERT_EQ(os_map_count(&basic_128_map), 1,
+ "Expect map to have 1 entries");
+
+ key.x[0] = 0xDEADDEAD;
+ key.x[1] = 0xBEEFBEEF;
+ value = (uint64_t)os_map_find(&basic_128_map, key);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 1");
+
+ key.x[0] = 0xCAFECAFE;
+ key.x[1] = 0xBABEBABE;
+ value = (uint64_t)os_map_find(&basic_128_map, key);
+ T_ASSERT_EQ(value, (uint64_t)0xCAFEBABE, "After-delete find 2");
+
+ key.x[0] = 0xCAFECAFE;
+ key.x[1] = 0xBABEBABE;
+ os_map_delete(&basic_128_map, key);
+
+ T_ASSERT_EQ(os_map_count(&basic_128_map), 0, "Expect map to be empty");
+
+ key.x[0] = 0xDEADDEAD;
+ key.x[1] = 0xBEEFBEEF;
+ value = (uint64_t)os_map_find(&basic_128_map, key);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 3");
+
+ key.x[0] = 0xCAFECAFE;
+ key.x[1] = 0xBABEBABE;
+ value = (uint64_t)os_map_find(&basic_128_map, key);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete find 4");
+
+ os_map_destroy(&basic_128_map);
+}
--- /dev/null
+/*
+* Copyright (c) 2020 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 <os/collections.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <darwintest.h>
+
+T_DECL(map_edge_64, "Make sure 64 bit map edge cases work",
+ T_META("owner", "Core Darwin Daemons & Tools"))
+{
+ os_map_64_t edge_64_map;
+ __block bool got_cafebabe = false;
+ __block bool got_deadbeaf = false;
+ __block bool got_beebait = false;
+ __block bool got_badfood = false;
+ uint64_t value;
+
+ T_LOG("Start");
+
+ // *** BASIC 64 bit key testing ***
+
+ os_map_init(&edge_64_map, NULL);
+
+ T_ASSERT_EQ(os_map_count(&edge_64_map), 0, "Expect map to be empty");
+
+ os_map_insert(&edge_64_map, 0x0, (void *)0xCAFEBABE);
+ os_map_insert(&edge_64_map, 0x1, (void *)0xDEADBEEF);
+ os_map_insert(&edge_64_map, 0x2, (void *)0xBEEB8);
+ os_map_insert(&edge_64_map, 0x3, (void *)0xBADF00D);
+
+ T_ASSERT_EQ(os_map_count(&edge_64_map), 4,
+ "Expect map to have 4 entries");
+
+ os_map_foreach(&edge_64_map, ^bool (uint64_t key, void *value){
+ T_LOG("Foreach called for 0x%llx, 0x%llx",
+ (unsigned long long)key, (unsigned long long)value);
+ if (key == 0x0) {
+ T_ASSERT_EQ(value, (void *)0xCAFEBABE,
+ "Callback expect 0xCAFEBABE");
+ got_cafebabe = true;
+ } else if (key == 0x1) {
+ T_ASSERT_EQ(value, (void *)0xDEADBEEF,
+ "Callback expect 0xDEADBEEF");
+ got_deadbeaf = true;
+ } else if (key == 0x2) {
+ T_ASSERT_EQ(value, (void *)0xBEEB8,
+ "Callback expect 0xBEEB8");
+ got_beebait = true;
+ } else if (key == 0x3) {
+ T_ASSERT_EQ(value, (void *)0xBADF00D,
+ "Callback expect 0xBADF00D");
+ got_badfood = true;
+ } else {
+ T_FAIL("Got unexpected callback 0x%llx, 0x%llx",
+ (unsigned long long)key,
+ (unsigned long long)value);
+ }
+ return true;
+ });
+
+ if (!got_cafebabe || !got_deadbeaf || !got_beebait || !got_badfood) {
+ T_FAIL("Failed to get callback");
+ }
+
+ value = (uint64_t)os_map_find(&edge_64_map, 0x0);
+ T_ASSERT_EQ(value, (uint64_t)0xCAFEBABE, "Find 1");
+
+ value = (uint64_t)os_map_find(&edge_64_map, 0x1);
+ T_ASSERT_EQ(value, (uint64_t)0xDEADBEEF, "Find 2");
+
+ value = (uint64_t)os_map_find(&edge_64_map, 0x2);
+ T_ASSERT_EQ(value, (uint64_t)0xBEEB8, "Find 3");
+
+ value = (uint64_t)os_map_find(&edge_64_map, 0x3);
+ T_ASSERT_EQ(value, (uint64_t)0xBADF00D, "Find 4");
+
+ os_map_delete(&edge_64_map, 0x0);
+ os_map_delete(&edge_64_map, 0x2);
+
+ T_ASSERT_EQ(os_map_count(&edge_64_map), 2,
+ "Expect map to have 2 entries");
+
+ value = (uint64_t)os_map_find(&edge_64_map, 0x0);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 1");
+
+ value = (uint64_t)os_map_find(&edge_64_map, 0x2);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 1");
+
+ value = (uint64_t)os_map_find(&edge_64_map, 0x1);
+ T_ASSERT_EQ(value, (uint64_t)0xDEADBEEF, "After-delete find 3");
+
+ value = (uint64_t)os_map_find(&edge_64_map, 0x3);
+ T_ASSERT_EQ(value, (uint64_t)0xBADF00D, "After-delete find 4");
+
+ os_map_delete(&edge_64_map, 0x1);
+ os_map_delete(&edge_64_map, 0x3);
+
+ T_ASSERT_EQ(os_map_count(&edge_64_map), 0, "Expect map to be empty");
+
+ value = (uint64_t)os_map_find(&edge_64_map, 0x1);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 5");
+
+ value = (uint64_t)os_map_find(&edge_64_map, 0x3);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete find 6");
+
+ os_map_destroy(&edge_64_map);
+}
+
+T_DECL(map_edge_32, "Make sure 32 bit map edge cases work",
+ T_META("owner", "Core Darwin Daemons & Tools"))
+{
+ os_map_32_t edge_32_map;
+ __block bool got_cafebabe = false;
+ __block bool got_deadbeaf = false;
+ __block bool got_beebait = false;
+ __block bool got_badfood = false;
+ uint64_t value;
+
+ T_LOG("Start");
+
+ // *** BASIC 64 bit key testing ***
+
+ os_map_init(&edge_32_map, NULL);
+
+ T_ASSERT_EQ(os_map_count(&edge_32_map), 0, "Expect map to be empty");
+
+ os_map_insert(&edge_32_map, 0x0, (void *)0xCAFEBABE);
+ os_map_insert(&edge_32_map, 0x1, (void *)0xDEADBEEF);
+ os_map_insert(&edge_32_map, 0x2, (void *)0xBEEB8);
+ os_map_insert(&edge_32_map, 0x3, (void *)0xBADF00D);
+
+ T_ASSERT_EQ(os_map_count(&edge_32_map), 4,
+ "Expect map to have 4 entries");
+
+ os_map_foreach(&edge_32_map, ^bool (uint32_t key, void *value){
+ T_LOG("Foreach called for 0x%llx, 0x%llx",
+ (unsigned long long)key, (unsigned long long)value);
+ if (key == 0x0) {
+ T_ASSERT_EQ(value, (void *)0xCAFEBABE,
+ "Callback expect 0xCAFEBABE");
+ got_cafebabe = true;
+ } else if (key == 0x1) {
+ T_ASSERT_EQ(value, (void *)0xDEADBEEF,
+ "Callback expect 0xDEADBEEF");
+ got_deadbeaf = true;
+ } else if (key == 0x2) {
+ T_ASSERT_EQ(value, (void *)0xBEEB8,
+ "Callback expect 0xBEEB8");
+ got_beebait = true;
+ } else if (key == 0x3) {
+ T_ASSERT_EQ(value, (void *)0xBADF00D,
+ "Callback expect 0xBADF00D");
+ got_badfood = true;
+ } else {
+ T_FAIL("Got unexpected callback 0x%llx, 0x%llx",
+ (unsigned long long)key,
+ (unsigned long long)value);
+ }
+ return true;
+ });
+
+ if (!got_cafebabe || !got_deadbeaf || !got_beebait || !got_badfood) {
+ T_FAIL("Failed to get callback");
+ }
+
+ value = (uint64_t)os_map_find(&edge_32_map, 0x0);
+ T_ASSERT_EQ(value, (uint64_t)0xCAFEBABE, "Find 1");
+
+ value = (uint64_t)os_map_find(&edge_32_map, 0x1);
+ T_ASSERT_EQ(value, (uint64_t)0xDEADBEEF, "Find 2");
+
+ value = (uint64_t)os_map_find(&edge_32_map, 0x2);
+ T_ASSERT_EQ(value, (uint64_t)0xBEEB8, "Find 3");
+
+ value = (uint64_t)os_map_find(&edge_32_map, 0x3);
+ T_ASSERT_EQ(value, (uint64_t)0xBADF00D, "Find 4");
+
+ os_map_delete(&edge_32_map, 0x0);
+ os_map_delete(&edge_32_map, 0x2);
+
+ T_ASSERT_EQ(os_map_count(&edge_32_map), 2,
+ "Expect map to have 2 entries");
+
+ value = (uint64_t)os_map_find(&edge_32_map, 0x0);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 1");
+
+ value = (uint64_t)os_map_find(&edge_32_map, 0x2);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 1");
+
+ value = (uint64_t)os_map_find(&edge_32_map, 0x1);
+ T_ASSERT_EQ(value, (uint64_t)0xDEADBEEF, "After-delete find 3");
+
+ value = (uint64_t)os_map_find(&edge_32_map, 0x3);
+ T_ASSERT_EQ(value, (uint64_t)0xBADF00D, "After-delete find 4");
+
+ os_map_delete(&edge_32_map, 0x1);
+ os_map_delete(&edge_32_map, 0x3);
+
+ T_ASSERT_EQ(os_map_count(&edge_32_map), 0, "Expect map to be empty");
+
+ value = (uint64_t)os_map_find(&edge_32_map, 0x1);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete Find 5");
+
+ value = (uint64_t)os_map_find(&edge_32_map, 0x3);
+ T_ASSERT_EQ(value, (uint64_t)0x0, "After-delete find 6");
+
+ os_map_destroy(&edge_32_map);
+}
+
--- /dev/null
+/*
+* Copyright (c) 2020 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@
+*/
+
+#import <TargetConditionals.h>
+#include <os/collections.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <darwintest.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <libproc.h>
+#include <sys/fcntl.h>
+
+
+// 11400714819323198485 is coprime with 2^64, so this will touch every number
+// before looping. It's also the closest number to 2^64 / the golden ratio, so
+// it will give a pretty even distribution
+static inline uint64_t _seq_next(uint64_t prev) {
+ return prev + 11400714819323198485llu;
+}
+
+#define MAPS_COUNT 4096
+#define ACTIONS_PER_MEASUREMENT_COUNT 512
+#define INSERT_TO_FIND_RATIO 64
+#define TOTAL_ITERATIONS 16
+
+#define PERF_OUTPUT_FILENAME "/tmp/libcollection_perf_data.csv"
+
+// This is fairly arbitrary, and just makes sure that any value bias is fairly
+// accounted for
+static inline uint64_t _value_for_key(uint64_t key) {
+ return key ^ 0xFFFF0000FF0000FF;
+}
+
+static uint64_t _insert_n_entries_to_maps(os_map_64_t *maps, uint64_t seed) {
+ uint64_t current_seq = seed;
+ for ( int i = 0; i < ACTIONS_PER_MEASUREMENT_COUNT; i++){
+ void *value = (void *)_value_for_key(current_seq);
+ for (int j = 0; j < MAPS_COUNT; j++) {
+ os_map_insert(&maps[j], current_seq, value);
+ }
+ current_seq = _seq_next(current_seq);
+ }
+ return current_seq;
+}
+
+static uint64_t _find_n_entries_in_maps(os_map_64_t *maps, uint64_t seed) {
+ uint64_t current_seq = seed;
+ for ( int i = 0; i < ACTIONS_PER_MEASUREMENT_COUNT; i++){
+ for (int j = 0; j < MAPS_COUNT; j++) {
+ (void)os_map_find(&maps[j], current_seq);
+ }
+ current_seq = _seq_next(current_seq);
+ }
+ return current_seq;
+}
+
+uint64_t absoluteTimeFromMachTime(uint64_t machTime) {
+ // get the mach timescale
+ static double __TimeScale = 0.0;
+ if (__TimeScale == 0.0) {
+ struct mach_timebase_info info;
+ if (mach_timebase_info(&info) == KERN_SUCCESS) {
+ __TimeScale = ((double)info.numer / (double)info.denom);
+ }
+ }
+ return (uint64_t)(machTime * __TimeScale);
+}
+
+static uint64_t
+_get_dirtymemory()
+{
+ int rval = 0;
+ struct rusage_info_v4 rusage;
+ if (proc_pid_rusage(getpid(), RUSAGE_INFO_V4, (rusage_info_t)&rusage)) {
+ rval = errno;
+ T_FAIL("rusage failed with %d", rval);
+ return 0;
+ } else {
+ return rusage.ri_phys_footprint;
+ }
+}
+
+T_DECL(map_perf, "Test map performance for small hash maps",
+ T_META("owner", "Core Darwin Daemons & Tools"),
+ T_META_CHECK_LEAKS(false),
+ T_META_ASROOT(true))
+{
+#if !(TARGET_OS_IOS | TARGET_OS_OSX)
+ T_PASS("Map_perf doesn't run on this platform");
+ return;
+#endif
+
+ os_map_64_t perf_maps[MAPS_COUNT];
+
+ for (int i = 0; i < MAPS_COUNT; i++) {
+ os_map_init(&perf_maps[i], NULL);
+ }
+
+ uint64_t current_seq = _seq_next(0);
+
+
+ int output_fd = creat(PERF_OUTPUT_FILENAME, S_IWUSR);
+ assert(output_fd);
+ FILE *output_file = fdopen(output_fd, "w");
+ assert(output_file);
+
+ fprintf(output_file,
+ "MAP_SIZE,INSERT_TIME,FIND_TIME,FIND_MISSING_TIME,MEM_USAGE\n");
+
+ uint64_t baseline_memory_usage = _get_dirtymemory();
+ T_LOG("Baseline memory usage is %llu", baseline_memory_usage);
+
+ for (int i = 0; i < TOTAL_ITERATIONS; i++) {
+ uint64_t map_size = ACTIONS_PER_MEASUREMENT_COUNT * (i + 1);
+ T_LOG("Starting performance testing with map size %llu",
+ map_size);
+
+ uint64_t insert_start_mach_time = mach_absolute_time();
+ uint64_t next_seq = _insert_n_entries_to_maps(perf_maps,
+ current_seq);
+ uint64_t insert_end_mach_time = mach_absolute_time();
+
+ uint64_t insert_start_time = absoluteTimeFromMachTime(insert_start_mach_time);
+ uint64_t insert_end_time = absoluteTimeFromMachTime(insert_end_mach_time);
+
+ T_LOG("Insertions complete, with start time %llu, end time %llu",
+ insert_start_time, insert_end_time);
+
+ uint64_t insert_average_time = ((insert_end_time - insert_start_time)) /
+ (MAPS_COUNT * ACTIONS_PER_MEASUREMENT_COUNT);
+
+ T_LOG("DATA: INSERTION TIME %llu, %llu", map_size,
+ insert_average_time);
+
+ uint64_t find_start_mach_time = mach_absolute_time();
+ for (int j = 0; j < INSERT_TO_FIND_RATIO; j++) {
+ _find_n_entries_in_maps(perf_maps, current_seq);
+ }
+ uint64_t find_end_mach_time = mach_absolute_time();
+
+ uint64_t find_start_time = absoluteTimeFromMachTime(find_start_mach_time);
+ uint64_t find_end_time = absoluteTimeFromMachTime(find_end_mach_time);
+
+ T_LOG("Finds complete, with start time %llu, end time %llu",
+ find_start_time, find_end_time);
+
+ uint64_t find_average_time = ((find_end_time - find_start_time)) /
+ (MAPS_COUNT * ACTIONS_PER_MEASUREMENT_COUNT * INSERT_TO_FIND_RATIO);
+
+ T_LOG("DATA: FIND TIME FOR %llu, %llu", map_size,
+ find_average_time);
+
+ uint64_t no_find_start_mach_time = mach_absolute_time();
+ for (int j = 0; j < INSERT_TO_FIND_RATIO; j++) {
+ _find_n_entries_in_maps(perf_maps, next_seq);
+ }
+ uint64_t no_find_end_mach_time = mach_absolute_time();
+
+ uint64_t no_find_start_time = absoluteTimeFromMachTime(no_find_start_mach_time);
+ uint64_t no_find_end_time = absoluteTimeFromMachTime(no_find_end_mach_time);
+
+ T_LOG("Find not present complete, with start time %llu, end time %llu",
+ no_find_start_time, no_find_end_time);
+
+ uint64_t no_find_average_time = ((no_find_end_time - no_find_start_time)) /
+ (MAPS_COUNT * ACTIONS_PER_MEASUREMENT_COUNT * INSERT_TO_FIND_RATIO);
+
+ T_LOG("DATA: NO-FIND TIME FOR %llu, %llu",
+ map_size, no_find_average_time);
+
+
+ uint64_t latest_memory_usage = _get_dirtymemory();
+ T_LOG("New memory usage is %llu", latest_memory_usage);
+
+ uint64_t average_memory_usage = latest_memory_usage / MAPS_COUNT;
+ T_LOG("DATA: MEMORY USAGE FOR %llu, %llu", map_size,
+ average_memory_usage);
+
+ fprintf(output_file, "%llu,%llu,%llu,%llu,%llu\n", map_size,
+ insert_average_time, find_average_time,
+ no_find_average_time, average_memory_usage);
+
+ current_seq = next_seq;
+ }
+
+ fclose(output_file);
+ close(output_fd);
+
+ T_PASS("Finished, output generated at: " PERF_OUTPUT_FILENAME);
+}
--- /dev/null
+/*
+* Copyright (c) 2020 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 <os/collections.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <darwintest.h>
+#include <stdlib.h>
+
+#define RANDOM_COUNT 256
+
+
+// Returns a random 32 bit integer
+static uint32_t random_32() {
+ uint32_t result = rand();
+ return result;
+}
+
+// Returns a random 64 bit integer thats not 0 or ~0
+static uint64_t random_64() {
+ return (uint64_t)random_32() | ((uint64_t)random_32() << 32);
+}
+
+static bool array_contains(uint32_t *array, int size, uint32_t entry) {
+ for (int i = 0; i < size; i++) {
+ if(array[i] == entry) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Returns a random 32 bit integer thats not in the array
+static uint32_t random_32_not_in_array(uint32_t *array, int size) {
+ uint32_t candidate;
+ do {
+ candidate = random_32();
+ } while (array_contains(array, size, candidate));
+ return candidate;
+}
+
+#define RUN_MAP_RANDOM(MAP, KEY_CONV) \
+{ \
+ T_LOG("Start run map for " #MAP); \
+ \
+ uint32_t keys[RANDOM_COUNT]; \
+ void *vals[RANDOM_COUNT]; \
+ \
+ os_map_init(&MAP, NULL); \
+ \
+ /* Insert random values for sequential keys to the map */ \
+ for (int i = 0; i < RANDOM_COUNT; i++) { \
+ uint32_t key = random_32_not_in_array(keys, i); \
+ void *val = (void *)random_64(); \
+ T_LOG("Inserting 0x%x, 0x%llx", key, (unsigned long long)val); \
+ os_map_insert(&MAP, KEY_CONV(key), val); \
+ keys[i] = key; \
+ vals[i] = val; \
+ } \
+ \
+ /* Find all the values */ \
+ for (int i = 0; i < RANDOM_COUNT; i++) { \
+ uint32_t key = keys[i]; \
+ void *expected_val = vals[i]; \
+ void *actual_val = os_map_find(&MAP, KEY_CONV(key)); \
+ if (expected_val == actual_val) { \
+ T_PASS("Found 0x%x, 0x%llx", key, \
+ (unsigned long long)expected_val); \
+ } else { \
+ T_FAIL("Incorrect find for 0x%x, Expected 0x%llx but got 0x%llx", \
+ key, (unsigned long long)expected_val, \
+ (unsigned long long)actual_val); \
+ } \
+ } \
+ \
+ /* Find some nonexistant values */ \
+ for (int i = 0; i < RANDOM_COUNT; i++) { \
+ uint32_t key = random_32_not_in_array(keys, RANDOM_COUNT); \
+ void *val = os_map_find(&MAP, KEY_CONV(key)); \
+ if (val == NULL) { \
+ T_PASS("Did not find value for nonexistant key 0x%x", \
+ key); \
+ } else { \
+ T_FAIL("Found value for nonexistant key 0x%x (0x%llx)", \
+ key, (unsigned long long)val); \
+ } \
+ } \
+ \
+ /* Remove half of the values */ \
+ for (int i = 0; i < RANDOM_COUNT; i+=2) { \
+ uint32_t key = keys[i]; \
+ os_map_delete(&MAP, KEY_CONV(key)); \
+ vals[i] == NULL; \
+ } \
+ \
+ /* Find the half that are still there */ \
+ for (int i = 1; i < RANDOM_COUNT; i+=2) { \
+ uint32_t key = keys[i]; \
+ void *expected_val = vals[i]; \
+ void *actual_val = os_map_find(&MAP, KEY_CONV(key)); \
+ if (expected_val == actual_val) { \
+ T_PASS("Found 0x%x, 0x%llx", key, \
+ (unsigned long long)expected_val); \
+ } else { \
+ T_FAIL("Incorrect find for 0x%x, Expected 0x%llx but got 0x%llx", \
+ key, (unsigned long long)expected_val, \
+ (unsigned long long)actual_val); \
+ } \
+ } \
+ \
+ /* Find the half that aren't there */ \
+ for (int i = 0; i < RANDOM_COUNT; i+=2) { \
+ uint32_t key = keys[i]; \
+ void *val = os_map_find(&MAP, KEY_CONV(key)); \
+ if (val == NULL) { \
+ T_PASS("Did not find value for nonexistant key 0x%x", \
+ key); \
+ } else { \
+ T_FAIL("Found value for nonexistant key 0x%x (0x%llx)", \
+ key, (unsigned long long)val); \
+ } \
+ } \
+ \
+ os_map_destroy(&MAP); \
+}
+
+uint64_t key_conv_32_to_64(uint32_t key) {
+ return (uint64_t)key | ((uint64_t)key << 32);
+}
+
+uint32_t key_conv_32_to_32(uint32_t key) {
+ return key;
+}
+
+const char *key_conv_32_to_string(uint32_t key) {
+ // TODO: Make this not leak
+ char *output;
+ assert(asprintf(&output, "0x%x", key) > 0);
+ return (const char *)output;
+}
+
+T_DECL(map_random_64,
+ "Make sure 64 bit map works for a bunch of random entries",
+ T_META("owner", "Core Darwin Daemons & Tools"))
+{
+ os_map_64_t random_64_map;
+
+ RUN_MAP_RANDOM(random_64_map, key_conv_32_to_64);
+}
+
+T_DECL(map_random_32,
+ "Make sure 32 bit map works for a bunch of random entries",
+ T_META("owner", "Core Darwin Daemons & Tools"))
+{
+ os_map_32_t random_32_map;
+
+ RUN_MAP_RANDOM(random_32_map, key_conv_32_to_32);
+
+}
+
+T_DECL(map_random_string,
+ "Make sure string map works for a bunch of random entries",
+ T_META("owner", "Core Darwin Daemons & Tools"),
+ T_META_CHECK_LEAKS(false))
+{
+
+ os_map_str_t random_s_map;
+
+ RUN_MAP_RANDOM(random_s_map, key_conv_32_to_string);
+
+}
+
--- /dev/null
+#include <stdio.h>
+
+#include <darwintest.h>
+
+T_DECL(ctermid, "ctermid")
+{
+ char term[L_ctermid] = { '\0' };
+ char *ptr = ctermid(term);
+ T_EXPECT_EQ((void*)term, (void*)ptr, "ctermid should return the buffer it received");
+ T_EXPECT_GT(strlen(ptr), 0ul, "the controlling terminal should have a name");
+}
+
+T_DECL(ctermid_null, "ctermid(NULL)")
+{
+ char *ptr = ctermid(NULL);
+ T_EXPECT_GT(strlen(ptr), 0ul, "the controlling terminal should have a name");
+}
* system(3) would be easier...
*/
char *hdiutil_argv[] = {
- "/usr/bin/hdiutil", "create", "-size", "5m", "-type", "UDIF",
+ "/usr/bin/hdiutil", "create", "-size", "10m", "-type", "UDIF",
"-volname", VOLNAME, "-nospotlight", "-fs", "HFS+", DMGFILE, "-attach",
NULL,
};
pid_t hdiutil_create = -1;
int ret = dt_launch_tool(&hdiutil_create, hdiutil_argv, false, NULL, NULL);
- T_ASSERT_POSIX_SUCCESS(ret, "created and attached 5MB DMG");
+ T_ASSERT_POSIX_SUCCESS(ret, "created and attached 10MB DMG");
+ T_ATEND(cleanup_dmg);
int status = 0;
pid_t waited = waitpid(hdiutil_create, &status, 0);
T_QUIET; T_ASSERT_EQ(waited, hdiutil_create,
T_ASSERT_EQ(WEXITSTATUS(status), 0,
"hdiutil should have exited successfully");
- T_ATEND(cleanup_dmg);
-
/*
* Open for updating, as previously only write-only files would be flushed
* on fclose.
T_ASSERT_NOTNULL(fp, "opened SystemVersion.plist");
struct stat sb;
T_ASSERT_POSIX_SUCCESS(fstat(fileno(fp), &sb), "fstat SystemVersion.plist");
- void *buf = malloc(sb.st_size * 2);
+ void *buf = malloc((size_t)(sb.st_size * 2));
T_ASSERT_NOTNULL(buf, "allocating buffer for size of SystemVersion.plist");
T_SETUPEND;
T_ASSERT_POSIX_SUCCESS(fseek(fp, 0, SEEK_SET), "seek to beginning");
// fread can return short *or* zero, according to manpage
- fread(buf, sb.st_size * 2, 1, fp);
- T_ASSERT_EQ(ftell(fp), sb.st_size, "tfell() == file size");
+ fread(buf, (size_t)(sb.st_size * 2), 1, fp);
+ T_ASSERT_EQ(ftell(fp), (long)sb.st_size, "ftell() == file size");
T_ASSERT_TRUE(feof(fp), "feof() reports end-of-file");
free(buf);
}
T_WITH_ERRNO;
T_ASSERT_NOTNULL(fp, "opened temporary file read/write");
T_WITH_ERRNO;
- T_ASSERT_EQ(fwrite("testing", 1, 7, fp), 7, "write temp contents");
+ T_ASSERT_EQ(fwrite("testing", 1, 7, fp), 7UL, "write temp contents");
(void)fclose(fp);
fp = fopen(fname, "r+");
T_ASSERT_POSIX_SUCCESS(fseek(fp, -1, SEEK_END), "seek to end - 1");
T_ASSERT_EQ(fgetc(fp), 'g', "fgetc should read 'g'");
T_ASSERT_EQ(fgetc(fp), EOF, "fgetc should read EOF");
- T_ASSERT_EQ(ftell(fp), 7, "tfell should report position 7");
+ T_ASSERT_EQ(ftell(fp), 7L, "ftell should report position 7");
int ret = fputc('!', fp);
T_ASSERT_POSIX_SUCCESS(ret,
"fputc to put an additional character in the FILE");
- T_ASSERT_EQ(ftell(fp), 8, "tfell should report position 8");
+ T_ASSERT_EQ(ftell(fp), 8L, "ftell should report position 8");
T_QUIET;
T_ASSERT_POSIX_SUCCESS(fclose(fp), "close temp file");
T_WITH_ERRNO;
T_ASSERT_NOTNULL(fp, "opened temporary file read/write");
T_WITH_ERRNO;
- T_ASSERT_EQ(fwrite("testing", 1, 7, fp), 7, "write temp contents");
+ T_ASSERT_EQ(fwrite("testing", 1, 7, fp), 7UL, "write temp contents");
(void)fclose(fp);
fp = fopen(fname, "r+");
--- /dev/null
+/* Thanks to the originator of Feedback FB8165838 / Radar 66131999 for
+ * writing the original version of this test!
+ */
+
+#include <darwintest.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <stdio.h>
+
+T_DECL(ftell_ungetc, "Test interactions of ftell and ungetc")
+{
+ FILE *fp = stdin;
+ fp = fopen("assets/ftell_ungetc.txt", "rb");
+ T_QUIET; T_ASSERT_NE(fp, (FILE*)NULL, "Open the file");
+
+ /* Test ftell without having done any reads/writes */
+ T_ASSERT_EQ(ftell(fp), 0L, "ftell without having done any reads/writes");
+
+ /* Read one character */
+ T_ASSERT_EQ(fgetc(fp), '/', "Read one charatcter");
+
+ /* Check ftell again after one read */
+ T_ASSERT_EQ(ftell(fp), 1L, "ftell after one read");
+
+ /* Push back one character */
+ T_ASSERT_EQ(ungetc('/', fp), '/', "push back one character");
+
+ /* Check ftell again after pushing back one char */
+ T_ASSERT_EQ(ftell(fp), 0L, "ftell after pushing back one char");
+
+ /* Read it again */
+ T_ASSERT_EQ(fgetc(fp), '/', "read pushed back character again");
+ T_ASSERT_EQ(ftell(fp), 1L, "ftell after reading again");
+
+ /* Seek and test ftell again */
+ T_ASSERT_EQ(fseek(fp, 2, SEEK_SET), 0, "seek");
+ T_ASSERT_EQ(ftell(fp), 2L, "ftell after seeking");
+
+ /* Push back invalid char (EOF) */
+ T_ASSERT_EQ(ungetc(EOF, fp), EOF, "push back invalid char");
+ T_ASSERT_EQ(ftell(fp), 2L, "ftell after pushing invalid char, pos should not have changed");
+
+ /* Read, push back different char, read again
+ * and check ftell.
+ *
+ * Cppreference:
+ * A successful call to ungetc on a text stream modifies
+ * the stream position indicator in unspecified manner but
+ * guarantees that after all pushed-back characters are
+ * retrieved with a read operation, the stream position
+ * indicator is equal to its value before ungetc.
+ */
+ T_ASSERT_EQ(fgetc(fp), '-', "read another character");
+ T_ASSERT_EQ(ftell(fp), 3L, "ftell after read");
+ T_ASSERT_EQ(ungetc('A', fp), 'A', "push back a different character");
+ T_ASSERT_EQ(fgetc(fp), 'A', "read back the different character");
+ T_ASSERT_EQ(ftell(fp), 3L, "ftell after pushback and read back");
+
+ /* Push back a non-read character and test ftell.
+ *
+ * According to POSIX:
+ * The file-position indicator is decremented by each
+ * successful call to ungetc();
+ *
+ * Cppreference:
+ * A successful call to ungetc on a binary stream decrements
+ * the stream position indicator by one
+ */
+ T_ASSERT_EQ(fgetc(fp), '+', "read another character");
+ T_ASSERT_EQ(ungetc('A', fp), 'A', "push back a different character");
+ T_EXPECTFAIL; T_ASSERT_EQ(ftell(fp), 3L, "ftell after pushback - EXPECTED FAIL rdar://66131999");
+}
--- /dev/null
+#include <err.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <fts.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <struct.h>
+#include <darwintest.h>
+#include <darwintest_utils.h>
+
+static void
+_create_random_file(int root_fd, char *path)
+{
+ int fd = openat(root_fd, path, O_WRONLY | O_CREAT);
+ T_ASSERT_POSIX_SUCCESS(fd, NULL);
+ T_ASSERT_POSIX_SUCCESS(dprintf(fd, "Random File at: %s", path), NULL);
+ T_ASSERT_POSIX_SUCCESS(close(fd), NULL);
+}
+
+static void
+_create_symlink(char *root, char *destination, char *source)
+{
+ char *absolute_destination = NULL;
+ T_ASSERT_POSIX_SUCCESS(asprintf(&absolute_destination, "%s/%s", root, destination), NULL);
+ char *absolute_source = NULL;
+ T_ASSERT_POSIX_SUCCESS(asprintf(&absolute_source, "%s/%s", root, source), NULL);
+ T_ASSERT_POSIX_SUCCESS(symlink(absolute_destination, absolute_source), NULL);
+ free(absolute_destination);
+ free(absolute_source);
+}
+
+static char *
+_remove_prefix(char *prefix, char *input) {
+ char *start = strstr(input, prefix);
+ T_QUIET;
+ T_ASSERT_NOTNULL(start, "prefix: %s input: %s", prefix, input);
+ char *end = start + strlen(prefix) + 1;
+ return end;
+}
+
+T_DECL(fts_simple, "Simple fts_read test")
+{
+ T_LOG("prog: %s", getprogname());
+ char *tmp_path = NULL;
+ T_ASSERT_POSIX_SUCCESS(asprintf(&tmp_path, "%s/%s-XXXXXX", dt_tmpdir(), T_NAME), NULL);
+ T_ASSERT_NOTNULL(mktemp(tmp_path), NULL);
+ T_ASSERT_POSIX_SUCCESS(mkdir(tmp_path, 0777), NULL);
+ int tmp_fd = open(tmp_path, O_RDONLY | O_DIRECTORY);
+ T_LOG("tmp: %s", tmp_path);
+ T_ASSERT_POSIX_SUCCESS(tmp_fd, NULL);
+
+ T_ASSERT_POSIX_SUCCESS(mkdirat(tmp_fd, "A", 0777), NULL);
+ T_ASSERT_POSIX_SUCCESS(mkdirat(tmp_fd, "A/B", 0777), NULL);
+ T_ASSERT_POSIX_SUCCESS(mkdirat(tmp_fd, "A/C", 0777), NULL);
+ T_ASSERT_POSIX_SUCCESS(mkdirat(tmp_fd, "A/B/D", 0777), NULL);
+ T_ASSERT_POSIX_SUCCESS(mkdirat(tmp_fd, "A/C/empty", 0777), NULL);
+ _create_random_file(tmp_fd, "root");
+ _create_random_file(tmp_fd, "A/fileA1");
+ _create_random_file(tmp_fd, "A/fileA2");
+ _create_random_file(tmp_fd, "A/B/fileB1");
+ _create_random_file(tmp_fd, "A/C/fileC1");
+ _create_random_file(tmp_fd, "A/B/D/fileD1");
+ T_ASSERT_POSIX_SUCCESS(mkdirat(tmp_fd, "LINK", 0777), NULL);
+ T_ASSERT_POSIX_SUCCESS(mkdirat(tmp_fd, "LINK/Z", 0777), NULL);
+ _create_random_file(tmp_fd, "LINK/fileL1");
+ _create_random_file(tmp_fd, "LINK/Z/fileZ1");
+ _create_symlink(tmp_path, "LINK", "A/link");
+
+ char original_cwd[MAXPATHLEN];
+ T_ASSERT_NOTNULL(getcwd(original_cwd, sizeof(original_cwd)), NULL);
+
+ struct {
+ const char *cwd;
+ const char *path;
+ int info;
+ bool found;
+ } expected[] = {
+ {
+ .cwd = original_cwd,
+ .path = "A",
+ .info = FTS_D,
+ },
+ {
+ .cwd = "A",
+ .path = "A/fileA2",
+ .info = FTS_F,
+ },
+ {
+ .cwd = "A",
+ .path = "A/B",
+ .info = FTS_D,
+ },
+ {
+ .cwd = "A/B",
+ .path = "A/B/D",
+ .info = FTS_D,
+ },
+ {
+ .cwd = "A/B/D",
+ .path = "A/B/D/fileD1",
+ .info = FTS_F,
+ },
+ {
+ .cwd = "A/B",
+ .path = "A/B/D",
+ .info = FTS_DP,
+ },
+ {
+ .cwd = "A/B",
+ .path = "A/B/fileB1",
+ .info = FTS_F,
+ },
+ {
+ .cwd = "A",
+ .path = "A/B",
+ .info = FTS_DP,
+ },
+ {
+ .cwd = "A",
+ .path = "A/C",
+ .info = FTS_D,
+ },
+ {
+ .cwd = "A/C",
+ .path = "A/C/empty",
+ .info = FTS_D,
+ },
+ {
+ .cwd = "A/C",
+ .path = "A/C/empty",
+ .info = FTS_DP,
+ },
+ {
+ .cwd = "A/C",
+ .path = "A/C/fileC1",
+ .info = FTS_F,
+ },
+ {
+ .cwd = "A",
+ .path = "A/C",
+ .info = FTS_DP,
+ },
+ {
+ .cwd = "A",
+ .path = "A/link",
+ .info = FTS_SL,
+ },
+ {
+ .cwd = "A",
+ .path = "A/link",
+ .info = FTS_D,
+ },
+ {
+ .cwd = "LINK",
+ .path = "A/link/fileL1",
+ .info = FTS_F,
+ },
+ {
+ .cwd = "LINK",
+ .path = "A/link/Z",
+ .info = FTS_D,
+ },
+ {
+ .cwd = "LINK/Z",
+ .path = "A/link/Z/fileZ1",
+ .info = FTS_F,
+ },
+ {
+ .cwd = "LINK",
+ .path = "A/link/Z",
+ .info = FTS_DP,
+ },
+ {
+ .cwd = "A",
+ .path = "A/link",
+ .info = FTS_DP,
+ },
+ {
+ .cwd = "A",
+ .path = "A/fileA1",
+ .info = FTS_F,
+ },
+ {
+ .cwd = original_cwd,
+ .path = "A",
+ .info = FTS_DP,
+ },
+ };
+
+ const char *LABELS[] = {
+ [0] = "None",
+ [FTS_D] = "FTS_D", /* preorder directory */
+ [FTS_DC] = "FTS_DC", /* directory that causes cycles */
+ [FTS_DEFAULT] = "FTS_DEFAULT", /* none of the above */
+ [FTS_DNR] = "FTS_DNR", /* unreadable directory */
+ [FTS_DOT] = "FTS_DOT", /* dot or dot-dot */
+ [FTS_DP] = "FTS_DP", /* postorder directory */
+ [FTS_ERR] = "FTS_ERR", /* error; errno is set */
+ [FTS_F] = "FTS_F", /* regular file */
+ [FTS_INIT] = "FTS_INIT", /* initialized only */
+ [FTS_NS] = "FTS_NS", /* stat(2) failed */
+ [FTS_NSOK] = "FTS_NSOK", /* no stat(2) requested */
+ [FTS_SL] = "FTS_SL", /* symbolic link */
+ [FTS_SLNONE] = "FTS_SLNONE", /* symbolic link without target */
+ };
+
+ char *root_path = NULL;
+ T_ASSERT_POSIX_SUCCESS(asprintf(&root_path, "%s/A", tmp_path), NULL);
+ const char *paths[] = {
+ root_path,
+ NULL,
+ };
+ FTS *tree = fts_open(paths, FTS_PHYSICAL, NULL);
+ T_ASSERT_NOTNULL(tree, NULL);
+ FTSENT *node;
+ int found_count = 0;
+ while ((node = fts_read(tree))) {
+ char cwd[MAXPATHLEN];
+ T_QUIET;
+ T_ASSERT_NOTNULL(getcwd(cwd, sizeof(cwd)), NULL);
+
+ switch (node->fts_info) {
+ case FTS_ERR:
+ T_FAIL("FTS_ERR(%d)", node->fts_errno);
+ break;
+ case FTS_SL:
+ fts_set(tree, node, FTS_FOLLOW);
+ /* fall through */
+ default: {
+ bool found = false;
+ for (size_t index = 0; index < countof(expected) && !found; index++) {
+ if (expected[index].found) {
+ continue;
+ }
+ if (expected[index].info != node->fts_info) {
+ // Wrong type, skip
+ continue;
+ }
+
+ char *expected_path = expected[index].path;
+ char *actual_path = node->fts_path;
+ if (expected_path[0] != '/') {
+ actual_path = _remove_prefix(tmp_path, actual_path);
+ }
+
+ if (strcmp(actual_path, expected_path) == 0) {
+ char *expected_cwd = expected[index].cwd;
+ char *actual_cwd = cwd;
+ if (expected_cwd[0] != '/') {
+ // Relative path
+ actual_cwd = _remove_prefix(tmp_path, actual_cwd);
+ }
+ T_QUIET;
+ T_EXPECT_EQ_STR(actual_cwd, expected_cwd, NULL);
+ found = true;
+ expected[index].found = true;
+ found_count++;
+ }
+ }
+ T_EXPECT_TRUE(found, "path: %s info: %d [%s] cwd: %s", node->fts_path, node->fts_info, LABELS[node->fts_info], cwd);
+ }
+ }
+ }
+ T_QUIET;
+ T_EXPECT_EQ(found_count, countof(expected), NULL);
+ for (size_t index = 0; index < countof(expected); index++) {
+ T_QUIET;
+ T_EXPECT_TRUE(expected[index].found, "missing: path: %s info %d [%s]", expected[index].path, expected[index].info, LABELS[expected[index].info]);
+ }
+ fts_close(tree);
+ free(tmp_path);
+ free(root_path);
+}
--- /dev/null
+#include <os/boot_mode_private.h>
+#include <TargetConditionals.h>
+
+#include <darwintest.h>
+
+#if TARGET_OS_OSX
+T_DECL(os_boot_mode_basic, "Can't know our exact boot mode, but it should be fetchable")
+{
+ const char *boot_mode = "??????";
+ bool result = os_boot_mode_query(&boot_mode);
+ if (result && !boot_mode) {
+ boot_mode = "no-particular-mode";
+ }
+ T_ASSERT_TRUE(result, "os_boot_mode_query() success (%s)", boot_mode);
+ T_ASSERT_NE_STR(boot_mode, "??????", "we actually set the result");
+}
+#endif
T_MAYFAIL;
T_EXPECT_FALSE(os_variant_uses_ephemeral_storage("com.apple.Libc.tests"), NULL);
+
+ T_MAYFAIL;
+ T_EXPECT_TRUE(os_variant_check("com.apple.Libc.tests", "HasFullLogging"), NULL);
}
#define VARIANT_SKIP_EXPORTED
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
#include "../libdarwin/variant.c"
+#pragma clang diagnostic pop
T_DECL(os_variant_detailed, "Looks at individual checks")
{
T_EXPECT_TRUE(_check_disabled(VP_SECURITY), NULL);
}
+
+// Ignore the last NULL entry in _variant_map.
+#define VARIANTS_LEN (sizeof(_variant_map) / sizeof(_variant_map[0])) - 1
+
+T_DECL(os_variant_asciibetical,
+ "Check that the variant map is in asciibetical order")
+{
+ const char *prev_variant = _variant_map[0].variant;
+ for (size_t i = 1; i < VARIANTS_LEN; i++) {
+ const char *variant = _variant_map[i].variant;
+ T_EXPECT_GT(strcmp(variant, prev_variant), 0,
+ "Variant %s should be asciibetically after variant %s",
+ variant, prev_variant);
+ prev_variant = variant;
+ }
+}
+
+T_DECL(os_variant_copy_description,
+ "Check that the description matches what os_variant_check returns")
+{
+ T_SETUPBEGIN;
+ struct {
+ const char *variant;
+ bool seen;
+ } seen_variants[VARIANTS_LEN] = {};
+ for (size_t i = 0; i < VARIANTS_LEN; i++) {
+ seen_variants[i].variant = _variant_map[i].variant;
+ T_QUIET; T_ASSERT_NOTNULL(seen_variants[i].variant,
+ "copied variant %zu to test for", i);
+ }
+ T_SETUPEND;
+
+ char *variant_desc = os_variant_copy_description("com.apple.Libc.tests");
+ T_WITH_ERRNO; T_ASSERT_NOTNULL(variant_desc,
+ "copied os_variant description");
+ T_LOG("Got os_variant description: %s", variant_desc);
+
+ char *next_variant = variant_desc;
+ while (next_variant && next_variant[0] != '\0') {
+ char *variant_end = strchr(next_variant, ' ');
+ if (variant_end) {
+ variant_end[0] = '\0';
+ variant_end += 1;
+ }
+ for (size_t i = 0; i < VARIANTS_LEN; i++) {
+ if (strcmp(next_variant, seen_variants[i].variant) == 0) {
+ seen_variants[i].seen = true;
+ }
+ }
+ T_EXPECT_TRUE(os_variant_check("com.apple.Libc.tests", next_variant),
+ "Y: %s: os_variant_check should agree with description",
+ next_variant);
+ next_variant = variant_end;
+ }
+
+ for (size_t i = 0; i < VARIANTS_LEN; i++) {
+ if (!seen_variants[i].seen) {
+ T_EXPECT_FALSE(os_variant_check("com.apple.Libc.tests",
+ seen_variants[i].variant),
+ "N: %s: os_variant_check should return false for variant "
+ "missing from description", seen_variants[i].variant);
+ }
+ }
+
+ free(variant_desc);
+}
{
printf("osvariantutil status\n");
printf("osvariantutil parse <kern.osvariant_status>\n");
+ printf("osvariantutil check <OS_VARIANT_STRING\n");
+ printf(" For Example: osvariantutil check IsDarwinOS\n");
+ printf(" Refer variant_private.h for valid OS_VARIANT_STRING\n");
exit(1);
}
}
_restore_cached_check_status(status);
printf("Using status: %llx\n", status);
- } else {
+ } else if (argc == 3 && strcmp(argv[1], "check") == 0) {
+ if (os_variant_check("com.apple.osvariantutil", argv[2]) == true) {
+ printf("%s: true\n", argv[2]);
+ exit(0);
+ } else {
+ printf("%s: false\n", argv[2]);
+ exit(1);
+ }
+ } else {
usage();
}
bool2str(os_variant_uses_ephemeral_storage("com.apple.osvariantutil")));
printf("\tos_variant_is_recovery: %s\n",
bool2str(os_variant_is_recovery("com.apple.osvariantutil")));
+#if TARGET_OS_OSX
+ printf("\tos_variant_is_basesystem: %s\n",
+ bool2str(os_variant_is_basesystem("com.apple.osvariantutil")));
+#endif
+ printf("\tos_variant_has_full_logging: %s\n",
+ bool2str(os_variant_check("com.apple.osvariantutil", "HasFullLogging")));
printf("\nOS Variant Overrides:\n");
printf("\tCONTENT: %s\n", bool2str(_check_disabled(VP_CONTENT)));
printf("\tInternal Diags Profile: %s\n", bool2str(_check_internal_diags_profile()));
printf("\tFactory Content: %s\n", bool2str(_check_factory_content()));
printf("\tBaseSystem Content: %s\n", bool2str(_check_base_system_content()));
+ printf("\tdarwinOS Content: %s\n", bool2str(_check_darwinos_content()));
#endif
printf("\tCan Has Debugger: %s\n", bool2str(_check_can_has_debugger()));
--- /dev/null
+/*
+ * Copyright (c) 2020 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_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. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * 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_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <darwintest.h>
+#include <darwintest_utils.h>
+
+// This can either test libkern's sscanf, or stdio.h's.
+//#define TEST_LIBKERN
+
+#if defined(TEST_LIBKERN)
+static int libkern_isspace(char c);
+int libkern_sscanf(const char *ibuf, const char *fmt, ...);
+int libkern_vsscanf(const char *inp, char const *fmt0, va_list ap);
+# define isspace(C) libkern_isspace(C)
+# define sscanf(...) libkern_sscanf(__VA_ARGS__)
+# define vsscanf(...) libkern_vsscanf(__VA_ARGS__)
+# include "../libkern/stdio/scanf.c"
+#else
+# include <stdio.h>
+#endif
+
+T_DECL(scanf_empty, "empty")
+{
+ T_ASSERT_EQ_INT(sscanf("", ""), 0, "empty input and format");
+ T_ASSERT_EQ_INT(sscanf("", "match me"), EOF, "empty input");
+ T_ASSERT_EQ_INT(sscanf("lonely", ""), 0, "empty format");
+}
+
+T_DECL(scanf_percent, "percent")
+{
+ T_ASSERT_EQ_INT(sscanf("%", "%%"), 0, "two percent");
+}
+
+T_DECL(scanf_character, "character")
+{
+ char c;
+ for (char i = ' '; i <= '~'; ++i) {
+ char buf[] = { i, '\0' };
+ T_ASSERT_EQ_INT(sscanf(buf, "%c", &c), 1, "character matched");
+ T_ASSERT_EQ_INT(c, i, "character value");
+ }
+}
+
+T_DECL(scanf_characters, "characters")
+{
+ char c[] = { 'a', 'b', 'c', 'd', 'e' };
+ T_ASSERT_EQ_INT(sscanf("01234", "%4c", c), 1, "characters matched");
+ T_ASSERT_EQ_INT(c[0], '0', "characters value");
+ T_ASSERT_EQ_INT(c[1], '1', "characters value");
+ T_ASSERT_EQ_INT(c[2], '2', "characters value");
+ T_ASSERT_EQ_INT(c[3], '3', "characters value");
+ T_ASSERT_EQ_INT(c[4], 'e', "characters value wasn't overwritten");
+}
+
+T_DECL(scanf_string, "string")
+{
+ char s[] = { 'a', 'b', 'c', 'd', 'e' };
+ T_ASSERT_EQ_INT(sscanf("012", "%s", s), 1, "string matched");
+ T_ASSERT_EQ_STR(s, "012", "string value");
+ T_ASSERT_EQ_INT(s[4], 'e', "string value wasn't overwritten");
+ T_ASSERT_EQ_INT(sscanf("ABCDE", "%3s", s), 1, "string matched");
+ T_ASSERT_EQ_STR(s, "ABC", "string value");
+ T_ASSERT_EQ_INT(s[4], 'e', "string value wasn't overwritten");
+}
+
+T_DECL(scanf_decimal, "decimal")
+{
+ int num;
+ for (char i = 0; i <= 9; ++i) {
+ char buf[] = { i + '0', '\0' };
+ T_ASSERT_EQ_INT(sscanf(buf, "%d", &num), 1, "decimal matched");
+ T_ASSERT_EQ_INT(num, i, "decimal value");
+ }
+ for (char i = 10; i <= 99; ++i) {
+ char buf[] = { i / 10 + '0', i % 10 + '0', '\0' };
+ T_ASSERT_EQ_INT(sscanf(buf, "%d", &num), 1, "decimal matched");
+ T_ASSERT_EQ_INT(num, i, "decimal value");
+ }
+ for (char i = 0; i <= 9; ++i) {
+ char buf[] = { '-', i + '0', '\0' };
+ T_ASSERT_EQ_INT(sscanf(buf, "%d", &num), 1, "negative decimal matched");
+ T_ASSERT_EQ_INT(num, -i, "negative decimal value");
+ }
+ T_ASSERT_EQ_INT(sscanf("-2147483648", "%d", &num), 1, "INT32_MIN matched");
+ T_ASSERT_EQ_INT(num, INT32_MIN, "INT32_MIN value");
+ T_ASSERT_EQ_INT(sscanf("2147483647", "%d", &num), 1, "INT32_MAX matched");
+ T_ASSERT_EQ_INT(num, INT32_MAX, "INT32_MAX value");
+}
+
+T_DECL(scanf_integer, "integer")
+{
+ int num;
+ T_ASSERT_EQ_INT(sscanf("0", "%i", &num), 1, "octal integer matched");
+ T_ASSERT_EQ_INT(num, 0, "octal integer value");
+ for (char i = 0; i <= 7; ++i) {
+ char buf[] = { '0', i + '0', '\0' };
+ T_ASSERT_EQ_INT(sscanf(buf, "%i", &num), 1, "octal integer matched");
+ T_ASSERT_EQ_INT(num, i, "octal integer value");
+ }
+ for (char i = 0; i <= 9; ++i) {
+ char buf[] = { '0', 'x', i + '0', '\0' };
+ T_ASSERT_EQ_INT(sscanf(buf, "%i", &num), 1, "hex integer matched");
+ T_ASSERT_EQ_INT(num, i, "hex integer value");
+ }
+ for (char i = 10; i <= 15; ++i) {
+ char buf[] = { '0', 'x', i - 10 + 'a', '\0' };
+ T_ASSERT_EQ_INT(sscanf(buf, "%i", &num), 1, "hex integer matched");
+ T_ASSERT_EQ_INT(num, i, "hex integer value");
+ }
+}
+
+T_DECL(scanf_unsigned, "unsigned")
+{
+ unsigned num;
+ T_ASSERT_EQ_INT(sscanf("4294967295", "%u", &num), 1, "UINT32_MAX matched");
+ T_ASSERT_EQ_UINT(num, UINT32_MAX, "UINT32_MAX value");
+}
+
+T_DECL(scanf_octal, "octal")
+{
+ int num;
+ T_ASSERT_EQ_INT(sscanf("0", "%o", &num), 1, "octal matched");
+ T_ASSERT_EQ_INT(num, 0, "octal value");
+ for (char i = 0; i <= 7; ++i) {
+ char buf[] = { '0', i + '0', '\0' };
+ T_ASSERT_EQ_INT(sscanf(buf, "%o", &num), 1, "octal matched");
+ T_ASSERT_EQ_INT(num, i, "octal value");
+ }
+}
+
+T_DECL(scanf_hex, "hex")
+{
+ int num;
+ for (char i = 0; i <= 9; ++i) {
+ char buf[] = { '0', 'x', i + '0', '\0' };
+ T_ASSERT_EQ_INT(sscanf(buf, "%x", &num), 1, "hex matched");
+ T_ASSERT_EQ_INT(num, i, "hex value");
+ }
+ for (char i = 10; i <= 15; ++i) {
+ char buf[] = { '0', 'x', i - 10 + 'a', '\0' };
+ T_ASSERT_EQ_INT(sscanf(buf, "%x", &num), 1, "hex matched");
+ T_ASSERT_EQ_INT(num, i, "hex value");
+ }
+}
+
+T_DECL(scanf_read, "read")
+{
+ int val, num;
+ T_ASSERT_EQ_INT(sscanf("", "%n", &num), 0, "read matched");
+ T_ASSERT_EQ_INT(num, 0, "read count");
+ T_ASSERT_EQ_INT(sscanf("a", "a%n", &num), 0, "read matched");
+ T_ASSERT_EQ_INT(num, 1, "read count");
+ T_ASSERT_EQ_INT(sscanf("ab", "a%nb", &num), 0, "read matched");
+ T_ASSERT_EQ_INT(num, 1, "read count");
+ T_ASSERT_EQ_INT(sscanf("1234567", "%i%n", &val, &num), 1, "read matched");
+ T_ASSERT_EQ_INT(val, 1234567, "read value");
+ T_ASSERT_EQ_INT(num, 7, "read count");
+}
+
+T_DECL(scanf_pointer, "pointer")
+{
+ void *ptr;
+ if (sizeof(void*) == 4) {
+ T_ASSERT_EQ_INT(sscanf("0xdeadbeef", "%p", &ptr), 1, "pointer matched");
+ T_ASSERT_EQ_PTR(ptr, (void*)0xdeadbeef, "pointer value");
+ } else {
+ T_ASSERT_EQ_INT(sscanf("0xdeadbeefc0defefe", "%p", &ptr), 1, "pointer matched");
+ T_ASSERT_EQ_PTR(ptr, (void*)0xdeadbeefc0defefe, "pointer value");
+ }
+}
#include <errno.h>
#include <unistd.h>
#include <sys/resource.h>
+#include <stdlib.h>
+#include <sys/sysctl.h>
#include <darwintest.h>
#define FILE_LIMIT 100
+/*
+ * Validate:
+ * (1) the maximum number of fds allowed open per process
+ * implemented by the kernel matches what sysconf expects:
+ * 32 bit: OPEN_MAX
+ * 64 bit: RLIM_INFINITY
+ * (2) fopen does not fail when NOFILE is unlimited.
+ */
+T_DECL(stdio_PR_63187147_SC_STREAM_MAX, "_SC_STREAM_MAX test")
+{
+ struct rlimit rlim;
+ long stream_max, saved_stream_max, open_count, i;
+ int maxfilesperproc, err;
+ size_t maxfilesperproc_size = sizeof(maxfilesperproc);
+ FILE **fp = NULL;
+ const char *filename = "fopen_test";
+
+ T_SETUPBEGIN;
+
+ saved_stream_max = sysconf(_SC_STREAM_MAX);
+ T_LOG("Initial stream_max %ld", saved_stream_max);
+
+ /* Decide the maximum number of fds allowed by the kernel */
+ err = sysctlbyname("kern.maxfilesperproc", &maxfilesperproc, &maxfilesperproc_size, NULL, 0);
+ T_EXPECT_POSIX_SUCCESS(err, "sysctlbyname(\"kern.maxfilesperproc\") returned %d", err);
+ T_LOG("kern.maxfilesperproc %d", maxfilesperproc);
+
+ /*
+ * Raise RLIMIT_NOFILE to RLIM_INFINITY, note that this does NOT update
+ * __stream_max in findfp.c
+ */
+ err = getrlimit(RLIMIT_NOFILE, &rlim);
+ T_EXPECT_POSIX_SUCCESS(err, "getrlimit(RLIMIT_NOFILE)");
+ T_LOG("Initial RLIMIT_NOFILE rlim.cur: 0x%llx", rlim.rlim_cur);
+ rlim.rlim_cur = RLIM_INFINITY;
+ err = setrlimit(RLIMIT_NOFILE, &rlim);
+ T_EXPECT_POSIX_SUCCESS(err, "setrlimit(RLIMIT_NOFILE) to RLIM_INFINITY");
+ err = getrlimit(RLIMIT_NOFILE, &rlim);
+ T_EXPECT_POSIX_SUCCESS(err, "New RLIMIT_NOFILE rlim_cur: 0x%llx", rlim.rlim_cur);
+
+ T_SETUPEND;
+
+ /*
+ * Test 1 (sysconf with _SC_STREAM_MAX): the largest value sysconf
+ * returns for _SC_STREAM_MAX is OPEN_MAX (32 bit) or
+ * RLIM_INFINITY (64 bit)
+ */
+ stream_max = sysconf(_SC_STREAM_MAX);
+ T_EXPECT_NE_LONG((long)-1, stream_max, "stream_max %ld", stream_max);
+#if __LP64__
+ T_EXPECT_EQ((long)RLIM_INFINITY, stream_max, "sysconf returned 0x%lx", stream_max);
+#else
+ T_EXPECT_EQ((long)OPEN_MAX, stream_max, "sysconf returned 0x%lx", stream_max);
+#endif
+
+ /*
+ * Test 2 (__stream_max in findfp.c): exercise __sfp by calling fopen
+ * saved_stream_max + 1 times. Note that we call fopen() up to
+ * maxfilesperproc times in case fopen() goes nuts.
+ */
+ fp = malloc(sizeof(FILE *) * (size_t)maxfilesperproc);
+ T_EXPECT_NOTNULL(fp, "Allocated %d FILE pointers", maxfilesperproc);
+ for (i = 0; i < saved_stream_max + 1 && i < maxfilesperproc; i++) {
+ if (i == saved_stream_max) {
+ T_LOG("The very next fopen should trigger __sfp to update __stream_max and fopen shouldn't fail ");
+ }
+ fp[i] = fopen(filename, "r");
+ T_QUIET; T_EXPECT_NOTNULL(fp, "%ld: fopen(%s, \"r\")", i, filename);
+ }
+ open_count = i;
+
+ for (i = 0; i < open_count; i++) {
+ fclose(fp[i]);
+ }
+ free(fp);
+
+ T_LOG("saved_stream_max %ld stream_max %ld fopen %ld files", saved_stream_max, stream_max, open_count);
+}
+
T_DECL(stdio_PR_22813396, "STREAM_MAX is affected by changes to RLIMIT_NOFILE")
{
struct rlimit theLimit;
}
#if !TARGET_OS_BRIDGE
-T_DECL(strptime_asctime, "strptime->asctime")
-{
+T_DECL(strptime_asctime, "strptime->asctime",
+ T_META_REQUIRES_OS_VARIANT_NOT("IsDarwinOS")) {
char *test[] = {
"Sun, 6 Apr 2003 03:30:00 -0500",
"Sun, 6 Apr 2003 04:30:00 -0500",
#include <darwintest.h>
#include <darwintest_utils.h>
+T_GLOBAL_META(T_META_REQUIRES_OS_VARIANT_NOT("IsDarwinOS"));
+
T_DECL(strptime_PR_27004626, "strptime() should fail when a %t doesn't match anything")
{
struct tm tm;
--- /dev/null
+<?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>com.apple.private.spawn-subsystem-root</key>
+ <true/>
+</dict>
+</plist>
+
--- /dev/null
+/*
+* Copyright (c) 2019 Apple Inc. All rights reserved.
+*
+* @APPLE_OSREFERENCE_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. The rights granted to you under the License
+* may not be used to create, or enable the creation or redistribution of,
+* unlawful or unlicensed copies of an Apple operating system, or to
+* circumvent, violate, or enable the circumvention or violation of, any
+* terms of an Apple operating system software license agreement.
+*
+* 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_OSREFERENCE_LICENSE_HEADER_END@
+*/
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <spawn.h>
+#include <spawn_private.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "subsystem_test.h"
+
+#include <darwintest.h>
+#include <darwintest_utils.h>
+
+#define RANDOM_STRING_LEN 33
+
+#define HELPER_PATH "./subsystem_test_helper"
+
+/* Create the given file. Doesn't create directories. */
+static bool
+_create_file(char * const filepath)
+{
+ bool success = false;
+ int fd = open(filepath, O_CREAT | O_EXCL, 0666);
+
+ if (fd >= 0) {
+ close(fd);
+ success = true;
+ }
+
+ return success;
+}
+
+/* Fills the given buffer with a random alphanumeric string. */
+static void
+_generate_random_string(char * buf, size_t buf_len)
+{
+
+ static char _alphanumeric[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ size_t cur_byte = 0;
+
+ if (buf_len == 0) {
+ return;
+ }
+
+ for (cur_byte = 0; ((buf_len - cur_byte) > 1); cur_byte++) {
+ buf[cur_byte] = _alphanumeric[rand() % (sizeof(_alphanumeric) - 1)];
+ }
+
+ buf[cur_byte] = 0;
+
+ return;
+}
+
+/* Compares the contents of the given file with the buffer. */
+static int
+_check_file_contents(char * const filepath, char * const buf, size_t buf_len)
+{
+ int result = 1;
+ int fd = -1;
+ char file_buf[buf_len];
+
+ fd = open(filepath, O_RDONLY);
+
+ if (fd >= 0) {
+ read(fd, file_buf, buf_len);
+ close(fd);
+
+ result = memcmp(buf, file_buf, buf_len);
+ }
+
+ return result;
+}
+
+/* Spawn with the given args and attributes, and waits for the child. */
+static int
+_spawn_and_wait(char ** args, posix_spawnattr_t *attr)
+{
+ int pid;
+ int status;
+
+ if (posix_spawn(&pid, args[0], NULL, attr, args, NULL)) {
+ return -1;
+ }
+ if (waitpid(pid, &status, 0) < 0) {
+ return -1;
+ }
+
+ if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)) {
+ return 0;
+ }
+
+ return -1;
+}
+
+T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
+
+T_DECL(subsystem,
+ "Test the subsystem-related functions",
+ T_META_CHECK_LEAKS(false))
+{
+ int result = 0;
+ int pid = 0;
+ posix_spawnattr_t attr = NULL;
+
+ char file_name[RANDOM_STRING_LEN];
+ char overflow_file_name[PATH_MAX - RANDOM_STRING_LEN];
+ char subsystem_name[RANDOM_STRING_LEN];
+
+ char file_path[PATH_MAX];
+ char subsystem_path[PATH_MAX];
+ char subsystem_tmp_path[PATH_MAX];
+ char subsystem_file_path[PATH_MAX];
+ char overflow_file_path[PATH_MAX];
+ char overflow_subsystem_file_path[PATH_MAX];
+
+ char * args[] = { HELPER_PATH, HELPER_BEHAVIOR_NOT_SET, overflow_file_path, "", NULL};
+
+ /* Seed rand() from /dev/random, and generate our random file names. */
+ sranddev();
+ _generate_random_string(file_name, sizeof(file_name));
+ _generate_random_string(overflow_file_name, sizeof(overflow_file_name));
+ _generate_random_string(subsystem_name, sizeof(subsystem_name));
+
+ /* Generate pathnames. */
+ sprintf(file_path, "/tmp/%s", file_name);
+ sprintf(overflow_file_path, "/tmp/%s", overflow_file_name);
+ sprintf(subsystem_path, "/tmp/%s", subsystem_name);
+ sprintf(subsystem_tmp_path, "%s/tmp", subsystem_path);
+ sprintf(subsystem_file_path, "%s/%s", subsystem_path, file_path);
+
+ /*
+ * Initial setup for the test; we'll need our subsystem
+ * directory and a /tmp/ for it.
+ */
+ T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdir(subsystem_path, 0777), "Create subsystem directory");
+ T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdir(subsystem_tmp_path, 0777), "Create subsystem /tmp/ directory");
+ T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_init(&attr), "posix_spawnattr_init");
+
+ /* open and stat with no subsystem. */
+ args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
+ T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), -1, "open_with_subsystem with no subsystem");
+
+ args[1] = HELPER_BEHAVIOR_STAT_NONE;
+ T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with no subsystem");
+
+ T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_set_subsystem_root_path_np(&attr, subsystem_path), "Set subsystem root path");
+
+ /*
+ * Test behavior when there is no main file and the subsystem
+ * file path is longer than PATH_MAX.
+ */
+ args[1] = HELPER_BEHAVIOR_OPEN_OVERFLOW;
+
+ T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "open_with_subsystem with overflow");
+
+ args[1] = HELPER_BEHAVIOR_STAT_OVERFLOW;
+
+ T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with overflow");
+
+ /* O_CREAT is strictly disallowed; test this. */
+ args[1] = HELPER_BEHAVIOR_OPEN_O_CREAT;
+ args[2] = file_path;
+
+ T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "open_with_subsystem with O_CREAT");
+
+ /*
+ * Test valid use of open_with_subsystem and
+ * stat_with_subsystem. We've got 4 cases to
+ * test: neither file exists, the subsystem
+ * file exists, both files exist, and the
+ * main fail exists.
+ */
+ /* Neither file exists. */
+ args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
+
+ T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), -1, "open_with_subsystem with no file");
+
+ args[1] = HELPER_BEHAVIOR_STAT_NONE;
+
+ T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with no file");
+
+ /* Subsystem file exists. */
+ T_QUIET; T_ASSERT_TRUE(_create_file(subsystem_file_path), "Create subsystem file");
+
+ args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
+ args[3] = "with subsystem file";
+
+ result = _spawn_and_wait(args, &attr);
+
+ if (!result) {
+ result = _check_file_contents(subsystem_file_path, args[3], strlen(args[3]));
+ }
+
+ T_ASSERT_EQ_INT(result, 0, "open_with_subsystem with subsystem file");
+
+ args[1] = HELPER_BEHAVIOR_STAT_NOT_MAIN;
+
+ T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with subsystem file");
+
+ /* Both files exist. */
+ T_QUIET; T_ASSERT_TRUE(_create_file(file_path), "Create main file");
+
+ args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
+ args[3] = "with both files";
+
+ result = _spawn_and_wait(args, &attr);
+
+ if (!result) {
+ result = _check_file_contents(file_path, args[3], strlen(args[3]));
+ }
+
+ T_ASSERT_EQ_INT(result, 0, "open_with_subsystem with both files");
+
+ args[1] = HELPER_BEHAVIOR_STAT_MAIN;
+
+ T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with both files");
+
+ /* Main file exists. */
+ T_QUIET; T_EXPECT_POSIX_SUCCESS(unlink(subsystem_file_path), "Delete subsystem file");
+
+ args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
+ args[3] = "with main file";
+
+ result = _spawn_and_wait(args, &attr);
+
+ if (!result) {
+ result = _check_file_contents(file_path, args[3], strlen(args[3]));
+ }
+
+ T_ASSERT_EQ_INT(result, 0, "open_with_subsystem with main file");
+
+ args[1] = HELPER_BEHAVIOR_STAT_MAIN;
+
+ T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with main file");
+
+ /* We're done; clean everything up. */
+ T_QUIET; T_EXPECT_POSIX_SUCCESS(unlink(file_path), "Delete main file");
+ T_QUIET; T_EXPECT_POSIX_SUCCESS(rmdir(subsystem_tmp_path), "Remove subsystem /tmp/ directory");
+ T_QUIET; T_EXPECT_POSIX_SUCCESS(rmdir(subsystem_path), "Remove subsystem directory");
+ T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_destroy(&attr), "posix_spawnattr_destroy");
+}
--- /dev/null
+/*
+* Copyright (c) 2019 Apple Inc. All rights reserved.
+*
+* @APPLE_OSREFERENCE_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. The rights granted to you under the License
+* may not be used to create, or enable the creation or redistribution of,
+* unlawful or unlicensed copies of an Apple operating system, or to
+* circumvent, violate, or enable the circumvention or violation of, any
+* terms of an Apple operating system software license agreement.
+*
+* 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_OSREFERENCE_LICENSE_HEADER_END@
+*/
+
+#ifndef _SUBSYSTEM_TEST_H_
+#define _SUBSYSTEM_TEST_H_
+
+#define HELPER_BEHAVIOR_NOT_SET ""
+#define HELPER_BEHAVIOR_OPEN_OVERFLOW "open_overflow"
+#define HELPER_BEHAVIOR_STAT_OVERFLOW "stat_overflow"
+#define HELPER_BEHAVIOR_OPEN_O_CREAT "open_o_creat"
+#define HELPER_BEHAVIOR_STAT_NONE "stat_none"
+#define HELPER_BEHAVIOR_STAT_MAIN "stat_main"
+#define HELPER_BEHAVIOR_STAT_NOT_MAIN "stat_not_main"
+#define HELPER_BEHAVIOR_OPEN_AND_WRITE "open_and_write"
+
+#endif /* _SUBSYSTEM_TEST_H_ */
--- /dev/null
+/*
+* Copyright (c) 2019 Apple Inc. All rights reserved.
+*
+* @APPLE_OSREFERENCE_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. The rights granted to you under the License
+* may not be used to create, or enable the creation or redistribution of,
+* unlawful or unlicensed copies of an Apple operating system, or to
+* circumvent, violate, or enable the circumvention or violation of, any
+* terms of an Apple operating system software license agreement.
+*
+* 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_OSREFERENCE_LICENSE_HEADER_END@
+*/
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <subsystem.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include "subsystem_test.h"
+
+#include <stdio.h>
+
+/*
+ * main expects 3 arguments:
+ * 1: Requested behavior (see subsystem_test.h)
+ * 2: Filepath to operate on
+ * 3: String to write to the file (if applicable)
+ */
+int
+main(int argc, char **argv)
+{
+ struct stat stat_buf;
+ int syscall_return = 0;
+ int retval = 1;
+ ino_t inode;
+ ino_t main_inode;
+
+ if (argc != 4) {
+ return retval;
+ }
+
+ char * behavior = argv[1];
+ char * filepath = argv[2];
+ char * write_string = argv[3];
+ size_t write_string_len = strlen(write_string) + 1;
+
+ if (!strcmp(behavior, HELPER_BEHAVIOR_OPEN_OVERFLOW)) {
+ /*
+ * Open with overflow case; expects a filepath longer
+ * than PATH_MAX.
+ */
+ syscall_return = open_with_subsystem(filepath, O_RDWR);
+
+ if (syscall_return < 0) {
+ if (errno == ENAMETOOLONG) {
+ retval = 0;
+ }
+ } else {
+ close(syscall_return);
+ }
+ } else if (!strcmp(behavior, HELPER_BEHAVIOR_STAT_OVERFLOW)) {
+ /*
+ * Stat with overflow case; expects a filepath longer
+ * than PATH_MAX.
+ */
+ syscall_return = stat_with_subsystem(filepath, &stat_buf);
+
+ if ((syscall_return < 0) && (errno == ENAMETOOLONG)) {
+ retval = 0;
+ }
+ }
+ if (!strcmp(behavior, HELPER_BEHAVIOR_OPEN_O_CREAT)) {
+ /*
+ * Open with O_CREAT case; O_CREAT should never work
+ * with open_with_subsystem.
+ */
+ syscall_return = open_with_subsystem(filepath, O_CREAT | O_RDWR);
+
+ if ((syscall_return < 0) && (errno == EINVAL)) {
+ retval = 0;
+ } else {
+ close(syscall_return);
+ }
+ } else if (!strcmp(behavior, HELPER_BEHAVIOR_STAT_NONE)) {
+ /*
+ * Stat when neither file is present.
+ */
+ syscall_return = stat_with_subsystem(filepath, &stat_buf);
+
+ if (syscall_return) {
+ retval = 0;
+ }
+ } else if (!strcmp(behavior, HELPER_BEHAVIOR_STAT_MAIN) ||
+ !strcmp(behavior, HELPER_BEHAVIOR_STAT_NOT_MAIN)) {
+ /*
+ * Stat when at least one file is present.
+ */
+ syscall_return = stat_with_subsystem(filepath, &stat_buf);
+
+ if (!syscall_return) {
+ inode = stat_buf.st_ino;
+
+ syscall_return = stat(filepath, &stat_buf);
+ if (!syscall_return) {
+ main_inode = stat_buf.st_ino;
+
+ /* Compare inodes based on the requested behavior. */
+ if (!strcmp(behavior, HELPER_BEHAVIOR_STAT_MAIN)) {
+ if (inode == main_inode) {
+ /* It was the main file. */
+ retval = 0;
+ }
+ } else if (!strcmp(behavior, HELPER_BEHAVIOR_STAT_NOT_MAIN)) {
+ if (inode != main_inode) {
+ /* It was the subsystem file. */
+ retval = 0;
+ }
+ }
+ } else if (!strcmp(behavior, HELPER_BEHAVIOR_STAT_NOT_MAIN)) {
+ /* If main doesn't exist, we found the subsystem file. */
+ retval = 0;
+ }
+ }
+ } else if (!strcmp(behavior, HELPER_BEHAVIOR_OPEN_AND_WRITE)) {
+ /*
+ * Open and write case; it is on the client to check that this
+ * wrote to the expected file.
+ */
+ syscall_return = open_with_subsystem(filepath, O_RDWR | O_TRUNC);
+
+ if (syscall_return >= 0) {
+ write(syscall_return, write_string, write_string_len);
+ close(syscall_return);
+ retval = 0;
+ }
+ }
+
+ return retval;
+}
--- /dev/null
+#include "<DEVELOPER_DIR>/Makefiles/CoreOS/Xcode/BSD.xcconfig"
+
+// Versioning
+
+// RC_ProjectSourceVersion unless it's unset, falling back to RECON_BUILD_VERSION_NONE
+Libcollections_BUILD_VERSION = $(<project>_BUILD_VERSION_$(<project>_BUILD_VERSION_SUFFIX_$(RC_ProjectSourceVersion)))
+
+Libcollections_BUILD_VERSION_ = $(RC_ProjectSourceVersion)
+Libcollections_BUILD_VERSION_SUFFIX_ = NONE
+
+// A high default value for when CURRENT_PROJECT_VERSION is unset (running `~rc/bin/buildit` with no version specified)
+collections_BUILD_VERSION_NONE = 60000
+
+CURRENT_PROJECT_VERSION = $(collections_BUILD_VERSION)
+DYLIB_CURRENT_VERSION = $(collections_BUILD_VERSION)
+MODULE_VERSION = $(collections_BUILD_VERSION)
+
+ARCHS = $(ARCHS_STANDARD)
+ONLY_ACTIVE_ARCH = NO
+ONLY_ACTIVE_ARCH[config=Debug] = YES
+ENABLE_TESTABILITY[config=Debug] = YES
+ALWAYS_SEARCH_USER_PATHS = NO
+USE_HEADERMAP = NO
+INFOPLIST_PREPROCESS = YES
+STRIP_INSTALLED_PRODUCT[config=Debug][sdk=*] = NO
+SKIP_INSTALL = NO
+OTHER_CFLAGS = -fverbose-asm
+SUPPORTS_TEXT_BASED_API = YES
+TAPI_VERIFY_MODE=Pedantic
+CODE_SIGN_IDENTITY = -
+
+// Compiler options
+
+GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS[config=Debug] = DEBUG=1
+
+GCC_C_LANGUAGE_STANDARD = gnu11
+CLANG_CXX_LANGUAGE_STANDARD = gnu++11
+GCC_OPTIMIZATION_LEVEL = s
+GCC_OPTIMIZATION_LEVEL[config=Debug] = 0
+CLANG_ENABLE_OBJC_ARC = YES
+CLANG_LINK_OBJC_RUNTIME = NO
+ENABLE_STRICT_OBJC_MSGSEND = YES
+GCC_ENABLE_BUILTIN_FUNCTIONS = YES
+GCC_ENABLE_CPP_EXCEPTIONS = NO
+GCC_ENABLE_PASCAL_STRINGS = NO
+GCC_NO_COMMON_BLOCKS = YES
+GCC_STRICT_ALIASING = YES
+GCC_SYMBOLS_PRIVATE_EXTERN = YES
+GCC_TREAT_WARNINGS_AS_ERRORS = YES
+
+HEADER_SEARCH_PATHS = $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders $(PROJECT_DIR)
+
+// Static analyzer
+
+CLANG_ANALYZER_DEADCODE_DEADSTORES = YES
+CLANG_ANALYZER_GCD = YES
+CLANG_ANALYZER_MEMORY_MANAGEMENT = YES
+CLANG_ANALYZER_NONNULL = YES
+CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES
+CLANG_ANALYZER_SECURITY_INSECUREAPI_GETPW_GETS = YES
+CLANG_ANALYZER_SECURITY_INSECUREAPI_MKSTEMP = YES
+CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES
+CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES
+CLANG_ANALYZER_SECURITY_INSECUREAPI_UNCHECKEDRETURN = YES
+CLANG_ANALYZER_SECURITY_INSECUREAPI_VFORK = YES
+CLANG_ANALYZER_SECURITY_KEYCHAIN_API = YES
+
+
+PRODUCT_NAME = collections
+INSTALL_PATH = /usr/lib/system
+PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/os
+PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/os
+DYLIB_CURRENT_VERSION = $(CURRENT_PROJECT_VERSION)
+EXECUTABLE_PREFIX = libsystem_
+BUILD_VARIANTS = normal
+CURRENT_PROJECT_VERSION = $(RC_ProjectSourceVersion)
+VERSION_INFO_PREFIX = __
+VERSIONING_SYSTEM = apple-generic
+GCC_SYMBOLS_PRIVATE_EXTERN = YES
+STRIP_STYLE = non-global
+
+SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator iphoneosnano iphonesimulatornano bridgeos
+
+LINK_WITH_STANDARD_LIBRARIES = NO
+OTHER_LDFLAGS = -umbrella System -L/usr/lib/system $(LDFLAGS_DYLD) $(LDFLAGS_COMPILER_RT) $(LDFLAGS_SYSCALL) $(LDFLAGS_MALLOC) $(LDFLAGS_C) $(LDFLAGS_BLOCKS) $(LDFLAGS_DARWIN)
+LDFLAGS_DYLD = -ldyld
+LDFLAGS_COMPILER_RT = -lcompiler_rt
+LDFLAGS_SYSCALL = -lsystem_kernel
+LDFLAGS_SYSCALL[sdk=iphonesimulator*] = -lsystem_sim_kernel
+LDFLAGS_MALLOC = -lsystem_malloc
+LDFLAGS_C = -lsystem_c
+LDFLAGS_BLOCKS = -lsystem_blocks
+LDFLAGS_DARWIN = -lsystem_darwin
my $platformName = $ENV{"VARIANT_PLATFORM_NAME"};
$platformName =~ s/simulator/os/;
+ # Try to find a platform+arch config file. If not found, try just
+ # a platform config file.
+ my $platformArchPath = $ENV{"SRCROOT"} . "/Platforms/" . $platformName . "/Makefile." . $arch . ".inc";
my $platformPath = $ENV{"SRCROOT"} . "/Platforms/" . $platformName . "/Makefile.inc";
+
my $featuresHeaderDir = $ENV{"DERIVED_FILES_DIR"}."/".$arch;
my $featuresHeader = $featuresHeaderDir."/libc-features.h";
- open FEATURESFILE, "<$platformPath" or die "Unable to open: $platformPath";
+ open FEATURESFILE, "<$platformArchPath" or open FEATURESFILE, "<$platformPath" or die "Unable to open: $platformArchPath nor $platformPath";
my %features = ();
my $skip = 0;
elsif ($unifdef == 0) {
# If we touch this file on every build, then every other iterative build in Xcode will rebuild *everything*
- my $platform_mtime = (stat($platformPath))[9];
+ my $platform_mtime = (stat($platformArchPath))[9];
+ if (!defined($platform_mtime)) {
+ # try the other one
+ $platform_mtime = (stat($platformPath))[9];
+ }
my $header_mtime = (stat($featuresHeader))[9];
if (defined($header_mtime) && defined($platform_mtime) && ($header_mtime > $platform_mtime)) {
)
XLOCALE_INSTHDRS=( "${INC_XLOCALE_INSTHDRS[@]/#/${SRCROOT}/include/xlocale/}" )
+MODULEMAPS=(
+ ${SRCROOT}/include/_types.modulemap
+ ${SRCROOT}/include/stdint.modulemap
+)
+
TYPES_INSTHDRS=(
${SRCROOT}/include/_types/_intmax_t.h
${SRCROOT}/include/_types/_nl_item.h
${SRCROOT}/nls/FreeBSD/msgcat.h
${SRCROOT}/gen/thread_stack_pcs.h
${SRCROOT}/libdarwin/h/dirstat.h
+ ${SRCROOT}/darwin/subsystem.h
)
OS_LOCALHDRS=( ${SRCROOT}/os/assumes.h ${SRCROOT}/os/debug_private.h )
${SRCROOT}/include/sys/rbtree.h
${SRCROOT}/include/sys/statvfs.h
)
+
PRIVUUID_INSTHDRS=( ${SRCROOT}/uuid/namespace.h )
else # DRIVERKITSDK
${MKDIR} ${INCDIR}/_types
${INSTALL} -m ${INSTALLMODE} ${TYPES_INSTHDRS[@]} ${INCDIR}/_types
fi
+if [ -n "${MODULEMAPS}" ]; then
+${MKDIR} ${INCDIR}
+${INSTALL} -m ${INSTALLMODE} ${MODULEMAPS[@]} ${INCDIR}
+fi
if [ -n "${LOCALHDRS}" ]; then
${MKDIR} ${LOCINCDIR}
${INSTALL} -m ${INSTALLMODE} ${LOCALHDRS[@]} ${LOCINCDIR}
--- /dev/null
+#!/bin/bash
+set -x
+if [ "${ACTION}" != "install" ]; then exit 0; fi
+if [ "${DRIVERKIT}" = 1 ]; then exit 0; fi
+
+MKDIR="mkdir -p"
+PLUTIL="plutil"
+
+SRC=$1
+FILENAME=$(basename $1)
+
+# Installs ErrnoErrors.strings into CoreTypes.bundle
+
+CORETYPESFRAMEWORK=${DSTROOT}/System/Library/CoreServices/CoreTypes.bundle
+${MKDIR} ${CORETYPESFRAMEWORK}/Contents/Resources/en.lproj
+${PLUTIL} -convert binary1 -o ${CORETYPESFRAMEWORK}/Contents/Resources/en.lproj/${FILENAME} $1
CR_LDFLAGS = -lCrashReporterClient
LIBCOMPILER_RT_LDFLAGS = -lcompiler_rt
LIBMALLOC_LDFLAGS = -lsystem_malloc
+LIBBLOCKS_LDFLAGS = -lsystem_blocks
LIBC_LDFLAGS = -lsystem_c
LIBDISPATCH_LDFLAGS = -ldispatch
LIBXPC_LDFLAGS = -lxpc
LIBSYSTEM_C_LDFLAGS = -all_load -nostdlib -L$(SDK_INSTALL_ROOT)/usr/lib/system -umbrella System $(CR_LDFLAGS) $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBM_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(UPWARD_LDFLAGS) $(LIBSYSTEM_C_EXTRA_LDFLAGS_$(CURRENT_ARCH)) -Wl,-interposable_list,$(DERIVED_FILES_DIR)/interposable.list -Wl,-unexported_symbols_list,$(DERIVED_FILES_DIR)/unexport.list -Wl,-alias_list,$(SRCROOT)/xcodescripts/alias.list -Wl,-order_file,$(SRCROOT)/xcodescripts/Libc.order @$(BUILT_PRODUCTS_DIR)/$(CURRENT_VARIANT).linklist
LIBSYSTEM_C_EXTRA_LDFLAGS_i386 = -Wl,-alias_list,$(SRCROOT)/xcodescripts/legacy_alias.list
+
// TODO: Remove upward links - mostly <rdar://problem/13183469>, macho is for assumes.c
-UPWARD_LDFLAGS = -Wl,-upward-ldispatch -Wl,-upward-lmacho -Wl,-upward-lsystem_asl -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_info -Wl,-upward-lsystem_notify -Wl,-upward-lxpc -Wl,-upward-lcorecrypto -Wl,-upward-lsystem_trace
+UPWARD_LDFLAGS = -Wl,-upward-ldispatch -Wl,-upward-lmacho -Wl,-upward-lsystem_asl -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_info -Wl,-upward-lsystem_notify -Wl,-upward-lxpc -Wl,-upward-lcorecrypto -Wl,-upward-lsystem_trace $(OTHER_UPWARD_LDFLAGS)
UPWARD_LDFLAGS[sdk=driverkit*] = -Wl,-upward-lmacho -Wl,-upward-lsystem_blocks -Wl,-upward-lcorecrypto
-LIBSYSTEM_DARWIN_LDFLAGS = -all_load -nostdlib -L$(SDK_INSTALL_ROOT)/usr/lib/system -umbrella System $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBM_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBC_LDFLAGS) $(LIBDISPATCH_LDFLAGS) $(LIBXPC_LDFLAGS)
+LIBSYSTEM_DARWIN_LDFLAGS = -all_load -nostdlib -L$(SDK_INSTALL_ROOT)/usr/lib/system -umbrella System $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBM_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBBLOCKS_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBC_LDFLAGS) $(LIBDISPATCH_LDFLAGS) $(LIBXPC_LDFLAGS) -lmacho -ldyld -Wl,-upward-lsystem_trace
// libPlatform.a architectures
ARCH_FAMILY = $(ARCH_FAMILY_$(CURRENT_ARCH))
TRE_CFLAGS = -DHAVE_CONFIG_H
TRE_SEARCH_PATHS = $(SRCROOT)/regex/TRE $(SRCROOT)/regex/FreeBSD
+// libc_dyld static library
+libc_dyld_CFLAGS = -fno-stack-check
+
// Files per architecture to exclude from the non-platform builds (because optimised versions exist in Platform)
BASE_INCLUDED_SOURCE_FILE_NAMES = $(BASE_INCLUDED_SOURCE_FILE_NAMES_$(ARCH_FAMILY))
BASE_EXCLUDED_SOURCE_FILE_NAMES = $(BASE_EXCLUDED_SOURCE_FILE_NAMES_$(ARCH_FAMILY)) $(BASE_EXCLUDED_SOURCE_FILE_NAMES_$(VARIANT_PLATFORM_NAME))
+++ /dev/null
-#!/bin/bash -ex
-
-if [[ "${ACTION}" == "installhdrs" ]]; then
- exit 0
-fi
-
-if [[ "${PLATFORM_NAME}" =~ "simulator" ]]; then
- ln -s libsystem_c.dylib ${DSTROOT}${INSTALL_PATH}/libsystem_sim_c.dylib
-fi
VARIANT_PRE1050_MACROS = $(VARIANT_PRE1050_MACROS_$(VARIANT_PLATFORM_NAME))
VARIANT_PRE1050_MACROS_macosx = -U__DARWIN_VERS_1050 -D__DARWIN_VERS_1050=0 -DVARIANT_PRE1050
VARIANT_PRE1050_INCLUDE = $(VARIANT_PRE1050_INCLUDE_$(VARIANT_PLATFORM_NAME))
-VARIANT_PRE1050_INCLUDE_macosx = daemon.c $(VARIANT_PRE1050_INCLUDE_$(VARIANT_PLATFORM_NAME)_$(CURRENT_ARCH))
+VARIANT_PRE1050_INCLUDE_macosx = $(VARIANT_PRE1050_INCLUDE_$(VARIANT_PLATFORM_NAME)_$(CURRENT_ARCH))
+VARIANT_PRE1050_INCLUDE_macosx_x86_64 = daemon.c
// Legacy symbols
VARIANT_LEGACY_MACROS = -U__DARWIN_UNIX03 -D__DARWIN_UNIX03=0 -U__DARWIN_64_BIT_INO_T -D__DARWIN_64_BIT_INO_T=0 -DVARIANT_LEGACY
VARIANT_DYLD_INCLUDE = $(VARIANT_DYLD_INCLUDE_generic) $(VARIANT_DYLD_INCLUDE_$(CURRENT_ARCH))
-VARIANT_DYLD_INCLUDE_generic = $(VARIANT_DYLD_INCLUDE_gen) $(VARIANT_DYLD_INCLUDE_stdlib) $(VARIANT_DYLD_INCLUDE_string) $(VARIANT_DYLD_INCLUDE_sys)
+VARIANT_DYLD_INCLUDE_generic = $(VARIANT_DYLD_INCLUDE_gen) $(VARIANT_DYLD_INCLUDE_stdlib) $(VARIANT_DYLD_INCLUDE_string) $(VARIANT_DYLD_INCLUDE_sys) $(VARIANT_DYLD_INCLUDE_darwin)
VARIANT_DYLD_INCLUDE_gen = arc4random.c closedir.c dirfd.c getcwd.c getpagesize.c nanosleep.c opendir.c readdir.c scandir.c sysctl.c sysctlbyname.c telldir.c usleep.c
VARIANT_DYLD_INCLUDE_stdlib = atexit.c exit.c gettimeofday.c heapsort.c merge.c qsort.c reallocf.c realpath.c
VARIANT_DYLD_INCLUDE_string = bcopy.c strcat.c strdup.c strrchr.c
VARIANT_DYLD_INCLUDE_sys = _libc_init.c
+VARIANT_DYLD_INCLUDE_darwin = subsystem.c