]> git.saurik.com Git - apple/libc.git/commitdiff
Libc-1439.40.11.tar.gz macos-1101 macos-112 v1439.40.11
authorApple <opensource@apple.com>
Wed, 18 Nov 2020 23:16:54 +0000 (23:16 +0000)
committerApple <opensource@apple.com>
Wed, 18 Nov 2020 23:16:54 +0000 (23:16 +0000)
96 files changed:
.upstream_base_commits
EAList2 [new file with mode: 0644]
Libc.xcodeproj/project.pbxproj
Platforms/macosx/Makefile.i386.inc [new file with mode: 0644]
Platforms/macosx/Makefile.inc
Platforms/macosx/Makefile.x86_64.inc [new file with mode: 0644]
collections/PublicHeader/_collections_map.h [new file with mode: 0644]
collections/PublicHeader/_collections_map.in.h [new file with mode: 0644]
collections/PublicHeader/collections.h [new file with mode: 0644]
collections/PublicHeader/collections_map.h [new file with mode: 0644]
collections/Source/collections_map.c [new file with mode: 0644]
collections/Source/collections_map.in.c [new file with mode: 0644]
collections/Source/collections_utilities.h [new file with mode: 0644]
darwin/ErrnoErrors.strings [new file with mode: 0644]
darwin/subsystem.c [new file with mode: 0644]
darwin/subsystem.h [new file with mode: 0644]
gen/FreeBSD/fmtmsg.c
gen/FreeBSD/getcwd.c
gen/FreeBSD/getmntinfo64.c
gen/FreeBSD/psignal.3
gen/FreeBSD/sysconf.c
gen/FreeBSD/sysctl.c
gen/FreeBSD/sysctl_internal.h [new file with mode: 0644]
gen/FreeBSD/sysctlbyname.c
gen/FreeBSD/sysctlnametomib.c
gen/FreeBSD/ualarm.c
gen/compat.5
gen/fts.c
include/_ctermid.h
include/_types.modulemap [new file with mode: 0644]
include/fts.h
include/libkern/OSThermalNotification.h
include/signal.h
include/stdint.modulemap [new file with mode: 0644]
include/stdio.h
include/stdlib.h
include/string.h
include/sys/acl.h
include/xlocale/_inttypes.h
include/xlocale/_wchar.h
libdarwin/ctl.c
libdarwin/dirstat.c
libdarwin/h/bsd.h
libdarwin/h/ctl.h
libdarwin/h/stdlib.h
libdarwin/internal.h
libdarwin/variant.c
locale/FreeBSD/collate.c
man/manpages.lst
net/byteorder.3
os/api.h
os/assumes.h
os/boot_mode_private.h [new file with mode: 0644]
os/linker_set.h
os/variant_private.h
stdio/FreeBSD/fclose.c
stdio/FreeBSD/findfp.c
stdlib/FreeBSD/atexit.c
stdlib/FreeBSD/psort_b.c [changed from file to symlink]
stdlib/FreeBSD/psort_r.c [changed from file to symlink]
stdlib/FreeBSD/realpath.3
stdlib/FreeBSD/strtonum.3 [new file with mode: 0644]
stdlib/FreeBSD/strtonum.c [new file with mode: 0644]
stdlib/NetBSD/strfmon.c
stdtime/FreeBSD/localtime.c
string/FreeBSD/strsignal.c
sys/_libc_init.c
tests/Makefile
tests/assets/ftell_ungetc.txt [new file with mode: 0644]
tests/collate.c [new file with mode: 0644]
tests/collections_basic.c [new file with mode: 0644]
tests/collections_edgecases.c [new file with mode: 0644]
tests/collections_perf.c [new file with mode: 0644]
tests/collections_random.c [new file with mode: 0644]
tests/ctermid.c [new file with mode: 0644]
tests/fflush.c
tests/ftell_ungetc.c [new file with mode: 0644]
tests/fts_simple.c [new file with mode: 0644]
tests/os_boot_mode.c [new file with mode: 0644]
tests/os_variant.c
tests/osvariantutil.c
tests/scanf.c [new file with mode: 0644]
tests/stdio.c
tests/stdtime.c
tests/strptime.c
tests/subsystem_test-entitlements.plist [new file with mode: 0644]
tests/subsystem_test.c [new file with mode: 0644]
tests/subsystem_test.h [new file with mode: 0644]
tests/subsystem_test_helper.c [new file with mode: 0644]
xcodescripts/collections.xcconfig [new file with mode: 0644]
xcodescripts/generate_features.pl
xcodescripts/headers.sh
xcodescripts/install_errorstrings.sh [new file with mode: 0755]
xcodescripts/libc.xcconfig
xcodescripts/sim-compat-symlink.sh [deleted file]
xcodescripts/variants.xcconfig

index f1fa5e84b93e065de354d7d895bbc5092bb5ee8f..52899fc333be7b6c3995cd5daa900afaa64666e4 100644 (file)
@@ -92,3 +92,6 @@ gen/FreeBSD/scandir_b.c       freebsd lib/libc/gen/scandir_b.c        0127b103f27578fc7f9cc33
 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
diff --git a/EAList2 b/EAList2
new file mode 100644 (file)
index 0000000..e69de29
index 2423e7a49440f67620394460fddddd9891a3b5cf..fba53dd4b95d3ded8ebe45b92c6685ccceb8ec2c 100644 (file)
@@ -7,6 +7,28 @@
        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" */;
@@ -36,7 +58,6 @@
                        );
                        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 = (
diff --git a/Platforms/macosx/Makefile.i386.inc b/Platforms/macosx/Makefile.i386.inc
new file mode 100644 (file)
index 0000000..d7c715b
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# 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
index b73ae877fcfd839b7be2d815c3089cdeeb56c3cf..32dd4bba0fdc520f243ac3acb54425b97600f85f 100644 (file)
@@ -18,15 +18,13 @@ FEATURE_LEGACY_UTMP_APIS = 1
 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
diff --git a/Platforms/macosx/Makefile.x86_64.inc b/Platforms/macosx/Makefile.x86_64.inc
new file mode 100644 (file)
index 0000000..76165fc
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# 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
diff --git a/collections/PublicHeader/_collections_map.h b/collections/PublicHeader/_collections_map.h
new file mode 100644 (file)
index 0000000..1824230
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+* 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 */
diff --git a/collections/PublicHeader/_collections_map.in.h b/collections/PublicHeader/_collections_map.in.h
new file mode 100644 (file)
index 0000000..02d0025
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+* 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
diff --git a/collections/PublicHeader/collections.h b/collections/PublicHeader/collections.h
new file mode 100644 (file)
index 0000000..9297674
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+* 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_
diff --git a/collections/PublicHeader/collections_map.h b/collections/PublicHeader/collections_map.h
new file mode 100644 (file)
index 0000000..6b6be21
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+* 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 */
diff --git a/collections/Source/collections_map.c b/collections/Source/collections_map.c
new file mode 100644 (file)
index 0000000..9bf1ad0
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+* 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
diff --git a/collections/Source/collections_map.in.c b/collections/Source/collections_map.in.c
new file mode 100644 (file)
index 0000000..170d860
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+* 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
+
diff --git a/collections/Source/collections_utilities.h b/collections/Source/collections_utilities.h
new file mode 100644 (file)
index 0000000..df09b82
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+* 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 */
diff --git a/darwin/ErrnoErrors.strings b/darwin/ErrnoErrors.strings
new file mode 100644 (file)
index 0000000..f733627
--- /dev/null
@@ -0,0 +1,323 @@
+/* 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";
diff --git a/darwin/subsystem.c b/darwin/subsystem.c
new file mode 100644 (file)
index 0000000..e591a3d
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+* 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;
+}
+
diff --git a/darwin/subsystem.h b/darwin/subsystem.h
new file mode 100644 (file)
index 0000000..e1a701a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+* 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__ */
index ada1c9dda8628c180c116ed59b5eab6e2934eebc..44ecc2f22ffcd4f94b9a8feb16a3cb876ff4880b 100644 (file)
@@ -122,14 +122,14 @@ def:
 
                        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 */
index 4a1989026b67df4e10f5b768c946d1646b5612ee..3951c7bf7a8185b15fc08797f5c58df5b3a6cd41 100644 (file)
@@ -49,10 +49,48 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/getcwd.c,v 1.29 2007/01/09 00:27:53 imp Exp
 #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,
@@ -253,8 +291,29 @@ __private_getcwd(pt, size, usegetpath)
                        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 (;;) {
index f4f3a28007db4dcdad84fc05557e5e955eaa3a89..fecb3fc42b728b8b092b5c4adc32c1fc28b349f0 100644 (file)
@@ -33,6 +33,8 @@ static char sccsid[] = "@(#)getmntinfo.c      8.1 (Berkeley) 6/4/93";
 #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>
@@ -66,3 +68,4 @@ getmntinfo64(mntbufp, flags)
        *mntbufp = mntbuf;
        return (mntsize);
 }
+#endif
index 84976af89d1f1c7ab7540af0a7fdb1cb098b042d..ca8d52df079d9c4b991501cc167134c4d22b4398 100644 (file)
@@ -34,6 +34,7 @@
 .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
@@ -63,6 +71,14 @@ function accepts a signal number argument
 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
@@ -103,6 +119,11 @@ and
 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
@@ -111,6 +132,23 @@ one of the following are true:
 .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 ,
index ca90c7a38630bd5f1d1eb6904f2b03f36f99a339..89425aabba2eb4d802e559571896575b48089377 100644 (file)
@@ -106,13 +106,36 @@ sysconf(name)
        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:
index c890aae011ac529b2e043c7d8b1de390dec4e1c6..3cbe7488a3d8cb85c69c79392b01beb5508fade0 100644 (file)
@@ -43,8 +43,8 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/sysctl.c,v 1.6 2007/01/09 00:27:55 imp Exp
 #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)
@@ -76,7 +76,15 @@ __attribute__((disable_tail_calls))
                        *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) {
diff --git a/gen/FreeBSD/sysctl_internal.h b/gen/FreeBSD/sysctl_internal.h
new file mode 100644 (file)
index 0000000..f42d711
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+* 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__ */
index c79d132b08bf453ccfb319dac9c8318920f59f7f..483a7caf9e78351d109aff6994752a6cea32d38e 100644 (file)
@@ -17,38 +17,22 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/sysctlbyname.c,v 1.5 2002/02/01 00:57:29 ob
 #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;
 }
 
index 3b19413ae2771434638e849606e5adec07ae1d40..e1592cbf3351565c498325636f9b4e86bc5f9e7e 100644 (file)
@@ -31,8 +31,7 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/sysctlnametomib.c,v 1.4 2003/01/04 00:11:11
 #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
index 23e816187840169731cf78e48c86d467fa391a07..c0d246d73c2af170c2d0be380aab07fae6bfc782 100644 (file)
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 1985, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
@@ -10,7 +12,7 @@
  * 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>
@@ -44,9 +46,7 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/ualarm.c,v 1.5 2007/01/09 00:27:56 imp Exp
  * 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;
 
@@ -58,6 +58,5 @@ ualarm(usecs, reload)
 
        if (setitimer(ITIMER_REAL, &new, &old) == 0)
                return (old.it_value.tv_sec * USPS + old.it_value.tv_usec);
-       /* else */
-               return (-1);
+       return (-1);
 }
index b711c04328e188abb3f56615433b22480c8b0885..c14ea42cc92c8686e5b1169073db9f0c26195472 100644 (file)
@@ -1,4 +1,4 @@
-.Dd June 30, 2010
+.Dd July 21, 2020
 .Os Darwin
 .Dt COMPAT 5
 .Sh NAME
@@ -6,6 +6,8 @@
 .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
@@ -34,6 +36,10 @@ The value of
 .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
index 2377f498de5c909fec6b825f000afeccf1e58342..77a0144e05e1e4f687ad18c178eb29d4851ba540 100644 (file)
--- a/gen/fts.c
+++ b/gen/fts.c
@@ -544,7 +544,7 @@ name:               t = sp->fts_path + NAPPEND(p->fts_parent);
                }
                (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);
@@ -1255,7 +1255,7 @@ common_no_stat:
         */
        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);
@@ -1571,6 +1571,41 @@ fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
        }
 #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;
index 540b1176228998cc4c1d7ec66b13c36d696d967d..5bbd721a0d6494543ca9ff931d1175b93b8ddcdb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
diff --git a/include/_types.modulemap b/include/_types.modulemap
new file mode 100644 (file)
index 0000000..758ee93
--- /dev/null
@@ -0,0 +1,22 @@
+// 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 * }
+}
index 325613704a24736c9bf2772b8e7935487b45e54c..f83c5cc03e653bf20ae40a0e053d746e77b29555 100644 (file)
@@ -119,7 +119,7 @@ typedef struct _ftsent {
        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) */
 
@@ -151,6 +151,7 @@ typedef struct _ftsent {
 #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 */
index e8581cc96639cd370581c3763ad5c957b0412f56..beeed587d196fcc72a4c9a2a44ba730e2029eae9 100644 (file)
@@ -40,7 +40,7 @@ __BEGIN_DECLS
 
 /* 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,
index a07abff19c67f3ea2678261f8fe5aaa31190b904..a3bb64b28e1ed605917b93df3d6b97e33610642c 100644 (file)
@@ -164,16 +164,11 @@ int       sigvec(int, struct sigvec *, struct sigvec *);
 __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)
diff --git a/include/stdint.modulemap b/include/stdint.modulemap
new file mode 100644 (file)
index 0000000..e279662
--- /dev/null
@@ -0,0 +1,52 @@
+// 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"
+                }
+        }
+}
index 07730d47f2f1c3d69b4eac8ba9b086093c8d779b..83ea979538884f08f0fca3a0581f10790003ff5d 100644 (file)
@@ -259,7 +259,7 @@ __END_DECLS
 /* 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)
index 7979ffa068082efea4f6168ea9bbbdeea65e639b..fdc95ad33df483d3618326e92be64ca3be337773 100644 (file)
@@ -205,7 +205,7 @@ unsigned long long
 #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)
@@ -441,6 +441,9 @@ int  sradixsort(const unsigned char **__base, int __nel, const unsigned char *__
 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
index a166d366ebdab265d85c196f95fba8476951579c..479c759af86171a288e9d7ed1f7c3950e724af6a 100644 (file)
@@ -184,6 +184,10 @@ void        swab(const void * __restrict, void * __restrict, ssize_t);
 __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
index 62240bfc87fedd96a7f340d78183670a06521f6b..fce4eafd0a8812f27594ab267395d62f7252da7e 100644 (file)
@@ -25,6 +25,7 @@
 
 #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
index db72853f8693ee94c19116d74759adba17436b76..8a7f563e378d0ae1715ea43a5c3e2d259516800f 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <sys/cdefs.h>
 #include <stdint.h>
+#include <stddef.h> /* wchar_t */
 #include <_xlocale.h>
 
 __BEGIN_DECLS
index 45daf4b5d21fc28128d8e1f947abaa3b36aaeb61..44ff9193ac89e56b9e9c25d2e69f71f644264a84 100644 (file)
@@ -27,6 +27,8 @@
 #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
index adcef271ba8fe823b0c2f9aac31209d0305417cc..28daa35ef84b661dc1d57bd598d177fac1e80166 100755 (executable)
@@ -2,8 +2,8 @@
 
 #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) \
@@ -31,6 +31,9 @@ static void _os_subcommand_print_usage(
 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;
@@ -40,6 +43,56 @@ static const os_subcommand_t __main_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,
@@ -85,7 +138,7 @@ static const os_subcommand_option_t _help_positional[] = {
                .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,
@@ -116,19 +169,14 @@ _help_invoke(const os_subcommand_t *osc, int argc, const char *argv[])
                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;
        }
 
@@ -139,20 +187,7 @@ _help_invoke(const os_subcommand_t *osc, int argc, const char *argv[])
        _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;
@@ -162,13 +197,17 @@ _help_invoke(const os_subcommand_t *osc, int argc, const char *argv[])
 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
@@ -199,8 +238,15 @@ _os_subcommand_copy_option_spec_short(const os_subcommand_t *osc,
                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);
@@ -238,8 +284,15 @@ _os_subcommand_copy_option_spec_long(const os_subcommand_t *osc,
                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);
@@ -270,7 +323,7 @@ _os_subcommand_copy_option_spec(const os_subcommand_t *osc,
                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);
                        }
@@ -355,13 +408,13 @@ _os_subcommand_copy_usage_line(const os_subcommand_t *osc)
                // 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);
@@ -376,38 +429,36 @@ _os_subcommand_print_option_usage(const os_subcommand_t *osc,
                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);
 }
 
@@ -420,35 +471,44 @@ _os_subcommand_print_usage(const os_subcommand_t *osc, FILE *f)
        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);
                }
        }
@@ -458,18 +518,14 @@ _os_subcommand_print_usage(const os_subcommand_t *osc, FILE *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);
                        }
                }
@@ -481,6 +537,10 @@ _os_subcommand_find(const char *name)
 {
        const os_subcommand_t **oscip = NULL;
 
+       if (!name) {
+               return _main_cmd;
+       }
+
        if (strcmp(_help_cmd->osc_name, name) == 0) {
                return &__help_cmd;
        }
@@ -501,6 +561,59 @@ _os_subcommand_find(const char *name)
        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[],
@@ -511,11 +624,7 @@ 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.
@@ -529,6 +638,13 @@ os_subcommand_main(int argc, const char *argv[],
 
        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);
@@ -569,19 +685,26 @@ os_subcommand_main(int argc, const char *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;
@@ -605,7 +728,7 @@ os_subcommand_vfprintf(const os_subcommand_t *osc, FILE *f,
        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);
index d62a521f7a6b6f14fae8322ef9a23de766cfebb4..885bcc1fefc8ad42f8914f2237cd9fefade0c85e 100644 (file)
@@ -219,6 +219,7 @@ fdirstat_fallback(int parent_fd, int flags, struct dirstat *ds)
 
                        if (fd < 0) {
                                DEBUGPRINT( "Unable to open directory %d:%s => %s\n", parent_fd, path, strerror(errno));
+                               free(path);
                                continue;
                        }
                }
index a33a9e0b80581c47865c43a0bf1f235c8e78e802..5df4697d6b10d68884c2470577d12868a9a817be 100644 (file)
@@ -100,11 +100,11 @@ sysctlbyname_get_data_np(const char *mibdesc, void **buff, size_t *buff_len);
  * 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
index 2968b5a7a4de5b95aa28bdd5dd1d4e261a87a87a..0953d49cf3ac12b7cf3da222f3f969a4ea4c1779 100644 (file)
@@ -175,12 +175,31 @@ typedef struct _os_subcommand os_subcommand_t;
  * @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),
 );
 
 /*!
@@ -293,6 +312,27 @@ typedef struct _os_subcommand_option {
  *
  * 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,
@@ -301,6 +341,8 @@ 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),
 );
 
 /*!
@@ -352,6 +394,11 @@ typedef int (*os_subcommand_invoke_t)(
  * 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
@@ -407,7 +454,7 @@ typedef int (*os_subcommand_invoke_t)(
  * @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;
@@ -419,6 +466,7 @@ struct _os_subcommand {
        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;
 };
 
 /*!
index 2d59ba3317337a37b936cb1db5118bf9f680023f..d2db938b95b7fddf4e239cd64ad2559f935500ea 100644 (file)
@@ -192,7 +192,7 @@ _os_strdup_known(const char *str)
 #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); \
index 25a29ba0d0c87ebadd9c9610da1faabde1c4dc85..78a38db0f44a153a2cb04333fd956170f3d5128a 100644 (file)
@@ -78,6 +78,7 @@
 #include <struct.h>
 #include <bootstrap_priv.h>
 #include <assert.h>
+#include <sys/ioctl.h>
 
 #include "h/bsd.h"
 #include "h/cleanup.h"
index 6e02d63b0223afccf2cfc4e2c7a1952421994b4d..684385671e1a01930471345b4bdf7cbe529b2250 100644 (file)
@@ -21,6 +21,7 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
+#include <errno.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/stat.h>
@@ -36,6 +37,7 @@
 #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
@@ -97,8 +99,11 @@ status2bool(enum check_status status) {
 #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"
 
@@ -168,6 +173,7 @@ static enum check_status internal_content = S_UNKNOWN;
 #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;
@@ -178,6 +184,7 @@ static enum check_status development_kernel = 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;
@@ -243,73 +250,83 @@ static bool _load_cached_status(void)
                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
@@ -352,21 +369,29 @@ static bool _parse_system_version_plist(void)
 
        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
@@ -377,11 +402,7 @@ static bool _check_factory_release_type(void)
 #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
@@ -392,11 +413,7 @@ static bool _check_darwin_release_type(void)
 #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
@@ -407,11 +424,7 @@ static bool _check_recovery_release_type(void)
 #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
@@ -419,79 +432,234 @@ static bool _check_recovery_release_type(void)
 
 #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
 
@@ -567,11 +735,10 @@ os_variant_has_factory_content(const char * __unused subsystem)
 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
 }
 
@@ -585,40 +752,28 @@ os_variant_is_recovery(const char * __unused subsystem)
 #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 ++;
        }
@@ -626,8 +781,149 @@ os_variant_check(const char * __unused subsystem, const char *variant)
        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
@@ -645,68 +941,80 @@ enum status_flags_positions {
        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;
 }
 
@@ -723,6 +1031,9 @@ static void _restore_cached_check_status(uint64_t status)
        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;
@@ -747,10 +1058,17 @@ static void _restore_cached_check_status(uint64_t status)
 
        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
index 028c182f1910d1e477cae7cda06b2c20ee35db4b..e5bc1eb14b76c9bac67c32f4518d71b88a8412dc 100644 (file)
@@ -393,12 +393,31 @@ largesearch(const wchar_t key, locale_t loc)
        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);
@@ -428,22 +447,41 @@ __collate_lookup_l(const wchar_t *t, int *len, int *prim, int *sec, locale_t 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)
 {
index 65ecdeba77c4a795db563363ed7446e820ecc936..337265c06274cdba79341b27d500a79ab543136b 100644 (file)
@@ -66,7 +66,7 @@ bsearch.3 bsearch.3 bsearch_b.3
 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
@@ -221,7 +221,7 @@ popen.3 popen.3 pclose.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
@@ -285,6 +285,7 @@ strtofflags.3 strtofflags.3 fflagstostr.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
index ce4eef2c875285516b8d3637c0f560bfe7a33400..83699d89c05e9f667b5c48c485c8b002a2bf4ca7 100644 (file)
 .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
@@ -71,13 +77,27 @@ and
 .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
index 43a37d0922f6963b03ca84232c2e25524294a173..fe6769984dfd1572fa294d86b10cd79a6c873532 100644 (file)
--- a/os/api.h
+++ b/os/api.h
@@ -71,7 +71,7 @@
  * 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
 
 /*!
index c5bca695b2a5e49096981c64119b1329023fbb38..ca7858fc090118aaf970e57c0350d5b9f274df4d 100644 (file)
@@ -43,8 +43,11 @@ __BEGIN_DECLS
 #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)
diff --git a/os/boot_mode_private.h b/os/boot_mode_private.h
new file mode 100644 (file)
index 0000000..0693839
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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__
index 2bf02a28aaa0d8e7e8524e27d2d856ab8a29173c..dc5a12042db4bf3d8a3097764594baf33f35a8a8 100644 (file)
@@ -62,7 +62,7 @@
  * 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
@@ -84,6 +84,7 @@
 # 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__
@@ -123,7 +133,7 @@ struct linker_set_entry {
 #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. :-) */
 
@@ -214,6 +224,7 @@ __linker_get_slide(struct mach_header *_header)
        }
        return 0;
 #else
+       (void)_header;
        return 0;
 #endif
 }
@@ -224,12 +235,12 @@ __attribute__((__const__));
 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 **
@@ -238,10 +249,10 @@ __attribute__((__const__));
 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);
index 5d6113e31ef9f7fe5e6873f872c14ed26805cfa0..835db8536f1c333b83ff98c3fd43d77072b934eb 100644 (file)
@@ -190,7 +190,7 @@ os_variant_is_darwinos(const char *subsystem);
 /*!
  * @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.
@@ -200,21 +200,47 @@ OS_EXPORT OS_WARN_RESULT
 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);
@@ -240,11 +266,33 @@ 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__
index 5a6183cae63bb731a05a7082c4c7eb8e6f8a042f..25a6cbbf4f561a8cd47b93d3c74587ca7e5dc70b 100644 (file)
@@ -48,6 +48,7 @@ int
 fclose(FILE *fp)
 {
        int r;
+       int error = 0;
 
        pthread_once(&__sdidinit, __sinit);
 
@@ -61,8 +62,13 @@ fclose(FILE *fp)
        }
        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))
@@ -73,5 +79,9 @@ fclose(FILE *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);
 }
index fe1110b0757ee51b9e0ed1fe82e23fbc150df431..233ca39d01147719c6782cd8ed4cb1afad74c914 100644 (file)
@@ -59,7 +59,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/findfp.c,v 1.34 2009/12/05 19:31:38 ed Ex
 
 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 */
@@ -78,17 +78,17 @@ pthread_once_t      __sdidinit;
   /* 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};
 
@@ -107,7 +107,7 @@ FILE *__stdinp = &__sF[0];
 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
@@ -162,14 +162,20 @@ __sfp(int count)
        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.
@@ -217,7 +223,7 @@ __private_extern__ void
 __sfprelease(FILE *fp)
 {
        if (fp->_counted) {
-               OSAtomicDecrement32(&__scounted);
+               OSAtomicDecrement64(&__scounted);
                fp->_counted = 0;
        }
        
@@ -278,7 +284,7 @@ _cleanup(void)
 void
 __sinit(void)
 {
-#if !TARGET_OS_EMBEDDED
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
        int i;
 #endif
 
@@ -287,7 +293,7 @@ __sinit(void)
        __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];
index 48ada4c3d7d4781223bdd32e7963b1ec518c7826..d5d6294df17117a6b2c89da7c6aaefab0f660ac5 100644 (file)
@@ -316,7 +316,7 @@ __cxa_finalize(const void *dso)
        }
 }
 
-#if !TARGET_IPHONE_SIMULATOR && (__i386__ || __x86_64__)
+#if TARGET_OS_OSX
 /*
  * Support for thread_local in C++, using existing _tlv_atexit() in libdyld
  */
deleted file mode 100644 (file)
index e9251ab945e16bea668babe5d6821f04db9ac8e2..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1,431 +0,0 @@
-/****************************************************************************/
-/*-
- * 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
-}
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..945c9b46d684f08ec84cb316e1dc0061e361f794
--- /dev/null
@@ -0,0 +1 @@
+.
\ No newline at end of file
deleted file mode 100644 (file)
index e9251ab945e16bea668babe5d6821f04db9ac8e2..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1,431 +0,0 @@
-/****************************************************************************/
-/*-
- * 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
-}
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..945c9b46d684f08ec84cb316e1dc0061e361f794
--- /dev/null
@@ -0,0 +1 @@
+.
\ No newline at end of file
index 740857b4edfa4aab347d3075f2b56744f0ea6efa..07e9dcc95546bf3ba50674eeb3f7e554421f77af 100644 (file)
@@ -104,7 +104,7 @@ Defining
 .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
diff --git a/stdlib/FreeBSD/strtonum.3 b/stdlib/FreeBSD/strtonum.3
new file mode 100644 (file)
index 0000000..ed26995
--- /dev/null
@@ -0,0 +1,155 @@
+.\" 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 .
diff --git a/stdlib/FreeBSD/strtonum.c b/stdlib/FreeBSD/strtonum.c
new file mode 100644 (file)
index 0000000..aa433d8
--- /dev/null
@@ -0,0 +1,68 @@
+/*-
+ * 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);
+}
index 8ee41da4c04e025972985d477bed3eee6f4ce346..262d183805908033393c9ddc499f4889c9f3ad50 100644 (file)
@@ -422,7 +422,7 @@ __setup_vars(int flags, char *cs_precedes, char *sep_by_space,
                *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;
@@ -433,7 +433,7 @@ __setup_vars(int flags, char *cs_precedes, char *sep_by_space,
                *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;
index ab37c66b696c4b52efc8fdc32fe59e257aad0c20..84a8c527a4dc438bbc1ebc7c3dce0a9ed380e02f 100644 (file)
@@ -187,7 +187,6 @@ struct rule {
 typedef struct {
        int token;
        int is_set;
-       int null_bootstrap;
 } notify_tz_t;
 
 #define NOTIFY_TZ_NAME         "com.apple.system.timezone"
@@ -382,8 +381,8 @@ __private_extern__ long             __darwin_altzone = 0;
 }
 #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 */
 
@@ -519,34 +518,6 @@ settzname(void)
 }
 
 #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)
 {
@@ -555,9 +526,6 @@ 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;
@@ -579,7 +547,8 @@ notify_register_tz(char *file, notify_tz_t *p)
        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;
        }
 
@@ -1553,27 +1522,50 @@ char *path;
                (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) {
@@ -1607,13 +1599,18 @@ tzsetwall_basic(int rdlocked)
 #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)
@@ -1703,14 +1700,16 @@ tzset_basic(int rdlocked)
                 * 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)
index 7806d63b35456e8e41fbc8748ecc3b69650ff5e5..052f9508b88f1ddb7d173a9adec302c6c6f458a5 100644 (file)
@@ -47,6 +47,14 @@ __FBSDID("$FreeBSD: src/lib/libc/string/strsignal.c,v 1.9 2010/01/24 10:35:26 um
 
 #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;
@@ -66,7 +74,7 @@ sig_tlsalloc(void)
            !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);
@@ -78,71 +86,74 @@ thr_err:
        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);
 }
index 3f95640c5ef0ab4113dadb8e1bc466e4ab15e589..d96428da4f17893e73e9dad58a2950f5fdfd2ebf 100644 (file)
@@ -44,6 +44,7 @@ extern void _init_clock_port(void);
 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,
@@ -59,6 +60,7 @@ _libc_initializer(const struct _libc_functions *funcs,
        __chk_init();
        __xlocale_init();
        __guard_setup(apple);
+       _subsystem_init(apple);
 }
 
 
index 3f6b561a457ada0f1c01d010c8c0137c34efc017..9ddf971392a8d98833024d004b1515db0598c8d8 100644 (file)
@@ -1,7 +1,7 @@
 PROJECT := Libc
 TEST_DIR := tests/
 
-CUSTOM_TARGETS += osvariantutil
+CUSTOM_TARGETS += osvariantutil subsystem_test_helper
 
 ifeq ($(DEVELOPER_DIR),)
     DEVELOPER_DIR := $(shell xcode-select -p)
@@ -11,6 +11,7 @@ include $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.common
 
 ifneq ($(PLATFORM),MacOSX)
 EXCLUDED_SOURCES += locale.c
+EXCLUDED_SOURCES += os_boot_mode.c
 endif
 
 FRAMEWORK_CFLAGS := $(patsubst %,-iframework %,$(SYSTEM_FRAMEWORK_SEARCH_PATHS))
@@ -20,9 +21,11 @@ WARNING_CFLAGS := -Weverything \
        -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
@@ -50,5 +53,16 @@ install-osvariantutil: osvariantutil
        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
+
diff --git a/tests/assets/ftell_ungetc.txt b/tests/assets/ftell_ungetc.txt
new file mode 100644 (file)
index 0000000..d0d6a6b
--- /dev/null
@@ -0,0 +1 @@
+/*-+ Hello! */
diff --git a/tests/collate.c b/tests/collate.c
new file mode 100644 (file)
index 0000000..207f71a
--- /dev/null
@@ -0,0 +1,280 @@
+#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
+}
diff --git a/tests/collections_basic.c b/tests/collections_basic.c
new file mode 100644 (file)
index 0000000..47be3ed
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+* 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);
+}
diff --git a/tests/collections_edgecases.c b/tests/collections_edgecases.c
new file mode 100644 (file)
index 0000000..da20eb3
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+* 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);
+}
+
diff --git a/tests/collections_perf.c b/tests/collections_perf.c
new file mode 100644 (file)
index 0000000..968a194
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+* 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);
+}
diff --git a/tests/collections_random.c b/tests/collections_random.c
new file mode 100644 (file)
index 0000000..298f5d1
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+* 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);
+
+}
+
diff --git a/tests/ctermid.c b/tests/ctermid.c
new file mode 100644 (file)
index 0000000..159be1c
--- /dev/null
@@ -0,0 +1,17 @@
+#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");
+}
index bd38edb288eed467f9ab57fde06cde20bdedb469..fa333ae89f89a5d0b0d3973be710bed9c40461c6 100644 (file)
@@ -197,13 +197,14 @@ T_DECL(fclose_enospc, "ensure ENOSPC is preserved on fclose")
         * 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,
@@ -214,8 +215,6 @@ T_DECL(fclose_enospc, "ensure ENOSPC is preserved on fclose")
        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.
@@ -349,14 +348,14 @@ T_DECL(ftell_feof,
        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);
 }
@@ -367,7 +366,7 @@ T_DECL(putc_flush, "ensure putc flushes to file on close") {
        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+");
@@ -377,12 +376,12 @@ T_DECL(putc_flush, "ensure putc flushes to file on close") {
        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");
@@ -405,7 +404,7 @@ T_DECL(putc_writedrop, "ensure writes are flushed with a pending read buffer") {
        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+");
diff --git a/tests/ftell_ungetc.c b/tests/ftell_ungetc.c
new file mode 100644 (file)
index 0000000..392ed17
--- /dev/null
@@ -0,0 +1,74 @@
+/* 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");
+}
diff --git a/tests/fts_simple.c b/tests/fts_simple.c
new file mode 100644 (file)
index 0000000..c9145ff
--- /dev/null
@@ -0,0 +1,277 @@
+#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);
+}
diff --git a/tests/os_boot_mode.c b/tests/os_boot_mode.c
new file mode 100644 (file)
index 0000000..47ceef8
--- /dev/null
@@ -0,0 +1,17 @@
+#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
index 70e820ba6ad0b1f3ae9ac34cbb8a376f39c4713f..340786e0e31a7a60252a5293ee3235df09cc9348 100644 (file)
@@ -28,11 +28,17 @@ T_DECL(os_variant_basic, "Just calls all the APIs")
 
        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")
 {
@@ -166,3 +172,69 @@ T_DECL(os_status_cache, "Checks saving and restoring of state")
 
        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);
+}
index 3d55240c8ae7111bd365102b433d49413d4a0d48..67e317ace2f38199dfc61ae4616b87c027ab180e 100644 (file)
@@ -12,6 +12,9 @@ usage(void)
 {
        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);
 }
 
@@ -31,7 +34,15 @@ main(int argc, char *argv[]) {
                }
                _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();
        }
 
@@ -52,6 +63,12 @@ main(int argc, char *argv[]) {
                        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)));
@@ -73,6 +90,7 @@ main(int argc, char *argv[]) {
        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()));
 
diff --git a/tests/scanf.c b/tests/scanf.c
new file mode 100644 (file)
index 0000000..7c7770d
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * 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");
+       }
+}
index dc0f1b55434cef6e3d629738b912a727fbe61393..ce45dc15e4543c7f1ed30e88b6a95516d8aca778 100644 (file)
@@ -3,11 +3,92 @@
 #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;
index c84735986d4d9e0d2c9a719c3dde5b836962af7b..ec97f1c344b2f66171c2c9ee7a042fb3c8c82d3b 100644 (file)
@@ -146,8 +146,8 @@ T_DECL(strptime_PR_10842560, "strptime() with %W and %U")
 }
 
 #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",
index b34fa1a863097310fce5bb51fe5bd1a0875eec39..e66d09cbafecd25588a14be0589a8747563762ed 100644 (file)
@@ -3,6 +3,8 @@
 #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;
diff --git a/tests/subsystem_test-entitlements.plist b/tests/subsystem_test-entitlements.plist
new file mode 100644 (file)
index 0000000..098c9bb
--- /dev/null
@@ -0,0 +1,9 @@
+<?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>
+
diff --git a/tests/subsystem_test.c b/tests/subsystem_test.c
new file mode 100644 (file)
index 0000000..7e584f7
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+* 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");
+}
diff --git a/tests/subsystem_test.h b/tests/subsystem_test.h
new file mode 100644 (file)
index 0000000..6244213
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+* 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_ */
diff --git a/tests/subsystem_test_helper.c b/tests/subsystem_test_helper.c
new file mode 100644 (file)
index 0000000..e27b8bd
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+* 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;
+}
diff --git a/xcodescripts/collections.xcconfig b/xcodescripts/collections.xcconfig
new file mode 100644 (file)
index 0000000..a8240ca
--- /dev/null
@@ -0,0 +1,93 @@
+#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
index e2da8f95c45adeb9658b11a3ed6eb506b418344a..e1bf9c620a08a817c572aceeedd6e882ccb66903 100755 (executable)
@@ -23,11 +23,15 @@ for my $arch (split(/ /, $ENV{"ARCHS"}))
        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;
@@ -94,7 +98,11 @@ for my $arch (split(/ /, $ENV{"ARCHS"}))
        
        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)) {
index 2c53924545579c66c239315ec05d0a949db937d0..312b10a3bfffe7f0ffebe2a6bdcd6e7715cb6baf 100755 (executable)
@@ -181,6 +181,11 @@ INC_XLOCALE_INSTHDRS=(
 )
 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
@@ -199,6 +204,7 @@ LOCALHDRS=(
        ${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 )
@@ -217,6 +223,7 @@ SYS_INSTHDRS=(
        ${SRCROOT}/include/sys/rbtree.h
        ${SRCROOT}/include/sys/statvfs.h
 )
+
 PRIVUUID_INSTHDRS=( ${SRCROOT}/uuid/namespace.h )
 
 else # DRIVERKITSDK
@@ -303,6 +310,10 @@ if [ -n "${TYPES_INSTHDRS}" ]; then
 ${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}
diff --git a/xcodescripts/install_errorstrings.sh b/xcodescripts/install_errorstrings.sh
new file mode 100755 (executable)
index 0000000..a1ff621
--- /dev/null
@@ -0,0 +1,16 @@
+#!/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
index 24e859b67ad175364636254d6e77dffac0ff98c1..9ab3f52e29ad26d76b1594e2f064972c4a87393a 100644 (file)
@@ -77,6 +77,7 @@ GCC_PREPROCESSOR_DEFINITIONS = $(BASE_PREPROCESSOR_MACROS)
 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
@@ -88,11 +89,12 @@ LIBDYLD_LDFLAGS = -ldyld
 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))
@@ -128,6 +130,9 @@ NetBSD_SEARCH_PATHS = $(SRCROOT)/nbsdcompat
 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))
diff --git a/xcodescripts/sim-compat-symlink.sh b/xcodescripts/sim-compat-symlink.sh
deleted file mode 100755 (executable)
index 7c1826a..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/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
index 68fd071c15f6e93b61564047eea5e68e75593049..9580ef59312bdb6239823a4ca324dbb210f94343 100644 (file)
@@ -37,7 +37,8 @@ VARIANT_DARWINEXTSN_CANCELABLE_MACROS = -DVARIANT_CANCELABLE -DVARIANT_DARWINEXT
 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
@@ -75,8 +76,9 @@ VARIANT_DYLD_MACROS = -UBUILDING_VARIANT -DVARIANT_STATIC -DVARIANT_CANCELABLE -
 
 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