2 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
28 #include <sys/sysctl.h>
29 #include <sys/types.h>
30 #include <dispatch/dispatch.h>
32 #include <xpc/private.h>
33 #include <System/sys/csr.h>
34 #include <System/machine/cpu_capabilities.h>
36 #include <os/assumes.h>
38 #include <os/stdlib.h>
39 #include <os/variant_private.h>
40 #include <os/boot_mode_private.h>
43 * Lists all properties overridden by an empty file
45 #define ALL_OVERRIDES_STR "content,diagnostics,ui,security"
47 enum variant_property
{
63 bool (*function
)(const char*);
64 } variant_check_mapping
;
67 status2bool(enum check_status status
) {
75 os_crash("os_variant had unexpected status");
79 #define VAR_FILE_LEGACY "/var/db/disableAppleInternal"
82 #define VAR_FILE_OVERRIDE "/var/db/os_variant_override"
84 #define VAR_FILE_OVERRIDE "/usr/share/misc/os_variant_override"
87 #if !TARGET_OS_SIMULATOR
88 #define INTERNAL_CONTENT_PATH "/System/Library/CoreServices/AppleInternalVariant.plist"
90 #define INTERNAL_CONTENT_PATH "/AppleInternal"
93 #define SYSTEM_VERSION_PLIST_PATH "/System/Library/CoreServices/SystemVersion.plist"
94 #define SYSTEM_VERSION_PLIST_KEY "ReleaseType"
97 #define INTERNAL_SETTINGS_PATH "/AppleInternal/Library/PreferenceBundles/Internal Settings.bundle"
99 #define INTERNAL_DIAGS_PROFILE_PATH "/var/db/ConfigurationProfiles/Settings/com.apple.InternalDiagnostics.plist"
100 #define FACTORY_CONTENT_PATH "/System/Library/CoreServices/AppleFactoryVariant.plist"
101 #define BASE_SYSTEM_CONTENT_PATH "/System/Library/BaseSystem"
102 #define DARWINOS_CONTENT_PATH "/System/Library/CoreServices/DarwinVariant.plist"
105 static void _check_all_statuses(void);
107 #if !TARGET_OS_SIMULATOR
108 #define CACHE_SYSCTL_NAME "kern.osvariant_status"
110 static void _restore_cached_check_status(uint64_t status
);
111 static uint64_t _get_cached_check_status(void);
113 static char * _read_file(const char *path
, size_t *size_out
)
117 int fd
= open(path
, O_RDONLY
);
118 if (fd
== -1) return NULL
;
121 int rc
= fstat(fd
, &sb
);
122 if (rc
!= 0 || sb
.st_size
== 0) {
126 size_t size_limit
= (size_out
&& *size_out
!= 0) ? *size_out
: 1024;
127 size_t size
= (size_t)sb
.st_size
;
128 if (size_out
) *size_out
= (size_t)sb
.st_size
;
129 if (size
> size_limit
) {
133 buf
= malloc(size
+ 1);
138 ssize_t bytes_read
= read(fd
, buf
, size
);
142 if (bytes_read
== (ssize_t
)size
) {
153 static xpc_object_t
read_plist(const char *path
)
155 size_t size
= 16 * 1024;
156 uint8_t *buf
= (uint8_t*)_read_file(path
, &size
);
157 if (!buf
) return NULL
;
159 xpc_object_t plist
= xpc_create_from_plist(buf
, size
);
160 if (plist
&& xpc_get_type(plist
) != XPC_TYPE_DICTIONARY
) {
171 #if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
172 static enum check_status internal_content
= S_UNKNOWN
;
174 #if !TARGET_OS_SIMULATOR
175 static enum check_status can_has_debugger
= S_UNKNOWN
;
176 static enum check_status has_full_logging
= S_UNKNOWN
;
178 static enum check_status internal_release_type
= S_UNKNOWN
;
179 static enum check_status factory_release_type
= S_UNKNOWN
;
180 static enum check_status darwin_release_type
= S_UNKNOWN
;
181 static enum check_status recovery_release_type
= S_UNKNOWN
;
182 static enum check_status development_kernel
= S_UNKNOWN
;
183 #else // TARGET_OS_IPHONE
184 static enum check_status internal_diags_profile
= S_UNKNOWN
;
185 static enum check_status factory_content
= S_UNKNOWN
;
186 static enum check_status base_system_content
= S_UNKNOWN
;
187 static enum check_status darwinos_content
= S_UNKNOWN
;
188 #endif // TARGET_OS_IPHONE
189 #endif // !TARGET_OS_SIMULATOR
190 static enum check_status is_ephemeral
= S_UNKNOWN
;
192 static bool disabled_status
[VP_MAX
] = {};
194 static void _parse_disabled_status(char *test_string
)
196 #if TARGET_OS_SIMULATOR
197 #pragma unused(test_string)
198 #else // TARGET_OS_SIMULATOR
199 char *override_str
= NULL
;
201 bzero(disabled_status
, sizeof(disabled_status
));
203 if (test_string
!= NULL
) {
204 /* used for unit tests */
205 override_str
= os_strdup(test_string
);
207 if (access(VAR_FILE_LEGACY
, F_OK
) == 0) {
208 override_str
= os_strdup(ALL_OVERRIDES_STR
);
209 } else if (access(VAR_FILE_OVERRIDE
, F_OK
) != 0) {
213 override_str
= _read_file(VAR_FILE_OVERRIDE
, NULL
);
216 if (override_str
== NULL
) {
217 override_str
= os_strdup(ALL_OVERRIDES_STR
);
220 char *token
, *string
= override_str
;
221 while ((token
= strsep(&string
, ",\n")) != NULL
) {
222 if (strcmp(token
, "content") == 0) {
223 disabled_status
[VP_CONTENT
] = true;
224 } else if (strcmp(token
, "diagnostics") == 0) {
225 disabled_status
[VP_DIAGNOSTICS
] = true;
226 } else if (strcmp(token
, "ui") == 0) {
227 disabled_status
[VP_UI
] = true;
228 } else if (strcmp(token
, "security") == 0) {
229 disabled_status
[VP_SECURITY
] = true;
235 #endif //!TARGET_OS_SIMULATOR
238 #if !TARGET_OS_SIMULATOR
239 static bool _load_cached_status(void)
242 size_t status_size
= sizeof(status
);
243 int ret
= sysctlbyname(CACHE_SYSCTL_NAME
, &status
, &status_size
, NULL
, 0);
249 _restore_cached_check_status(status
);
257 static void _initialize_status(void)
259 static dispatch_once_t once
;
260 dispatch_once(&once
, ^{
261 #if !TARGET_OS_SIMULATOR && !defined(VARIANT_SKIP_EXPORTED)
262 if (_load_cached_status() && !_os_xbs_chrooted
) {
266 _check_all_statuses();
270 static bool _check_disabled(enum variant_property variant_property
)
272 _initialize_status();
274 return disabled_status
[variant_property
];
277 #if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
278 static void _check_internal_content_impl(void)
280 if (_os_xbs_chrooted
&& internal_content
!= S_UNKNOWN
) {
283 os_assert(internal_content
== S_UNKNOWN
);
286 #if !TARGET_OS_SIMULATOR
287 const char * path
= INTERNAL_CONTENT_PATH
;
289 char *simulator_root
= getenv("IPHONE_SIMULATOR_ROOT");
290 char *to_free
= NULL
, *path
= NULL
;
291 if (simulator_root
) {
292 asprintf(&path
, "%s/%s", simulator_root
, INTERNAL_CONTENT_PATH
);
294 internal_content
= S_NO
;
300 internal_content
= (access(path
, F_OK
) == 0) ? S_YES
: S_NO
;
301 #if TARGET_OS_SIMULATOR
306 static bool _check_internal_content(void)
308 _initialize_status();
309 return status2bool(internal_content
);
311 #endif // !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
314 static void _check_factory_content_impl(void)
316 if (_os_xbs_chrooted
&& factory_content
!= S_UNKNOWN
) {
319 os_assert(factory_content
== S_UNKNOWN
);
322 const char * path
= FACTORY_CONTENT_PATH
;
323 factory_content
= (access(path
, F_OK
) == 0) ? S_YES
: S_NO
;
326 static bool _check_factory_content(void)
328 _initialize_status();
330 return status2bool(factory_content
);
332 #endif // TARGET_OS_OSX
336 #if !TARGET_OS_SIMULATOR
337 static bool _parse_system_version_plist(void)
339 xpc_object_t system_version_plist
= read_plist(SYSTEM_VERSION_PLIST_PATH
);
340 if (!system_version_plist
) {
344 const char *release_type
=
345 xpc_dictionary_get_string(system_version_plist
,
346 SYSTEM_VERSION_PLIST_KEY
);
348 if (release_type
== NULL
) {
350 * Confusingly, customer images are just completely missing this key.
352 internal_release_type
= S_NO
;
353 factory_release_type
= S_NO
;
354 darwin_release_type
= S_NO
;
355 recovery_release_type
= S_NO
;
356 } else if (strcmp(release_type
, "NonUI") == 0) {
357 factory_release_type
= S_YES
;
358 internal_release_type
= S_YES
;
359 darwin_release_type
= S_NO
;
360 recovery_release_type
= S_NO
;
362 factory_release_type
= S_NO
;
363 internal_release_type
= (strstr(release_type
, "Internal") != NULL
) ? S_YES
: S_NO
;
364 darwin_release_type
= (strstr(release_type
, "Darwin") != NULL
) ? S_YES
: S_NO
;
365 recovery_release_type
= (strstr(release_type
, "Recovery") != NULL
) ? S_YES
: S_NO
;
368 xpc_release(system_version_plist
);
373 static void _check_system_version_plist_statuses_impl(void)
375 os_assert(internal_release_type
== S_UNKNOWN
);
376 os_assert(factory_release_type
== S_UNKNOWN
);
377 os_assert(darwin_release_type
== S_UNKNOWN
);
378 os_assert(recovery_release_type
== S_UNKNOWN
);
380 if (!_parse_system_version_plist()) {
381 internal_release_type
= (access(INTERNAL_SETTINGS_PATH
, F_OK
) == 0) ? S_YES
: S_NO
;
382 factory_release_type
= S_NO
;
383 darwin_release_type
= S_NO
;
384 recovery_release_type
= S_NO
;
387 #endif //!TARGET_OS_SIMULATOR
389 static bool _check_internal_release_type(void)
391 #if TARGET_OS_SIMULATOR
392 return _check_internal_content();
393 #else // TARGET_OS_SIMULATOR
394 _initialize_status();
396 return status2bool(internal_release_type
);
397 #endif // TARGET_OS_SIMULATOR
400 static bool _check_factory_release_type(void)
402 #if TARGET_OS_SIMULATOR
404 #else // TARGET_OS_SIMULATOR
405 _initialize_status();
407 return status2bool(factory_release_type
);
408 #endif // TARGET_OS_SIMULATOR
411 static bool _check_darwin_release_type(void)
413 #if TARGET_OS_SIMULATOR
415 #else // TARGET_OS_SIMULATOR
416 _initialize_status();
418 return status2bool(darwin_release_type
);
419 #endif // TARGET_OS_SIMULATOR
422 static bool _check_recovery_release_type(void)
424 #if TARGET_OS_SIMULATOR
426 #else // TARGET_OS_SIMULATOR
427 _initialize_status();
429 return status2bool(recovery_release_type
);
430 #endif // TARGET_OS_SIMULATOR
433 #else // TARGET_OS_IPHONE
435 static void _check_internal_diags_profile_impl(void)
437 if (_os_xbs_chrooted
&& internal_diags_profile
!= S_UNKNOWN
) {
440 os_assert(internal_diags_profile
== S_UNKNOWN
);
443 xpc_object_t profile_settings
= read_plist(INTERNAL_DIAGS_PROFILE_PATH
);
444 if (profile_settings
) {
445 internal_diags_profile
= xpc_dictionary_get_bool(profile_settings
, "AppleInternal") ? S_YES
: S_NO
;
446 xpc_release(profile_settings
);
448 internal_diags_profile
= S_NO
;
452 static bool _check_internal_diags_profile(void)
454 _initialize_status();
456 return status2bool(internal_diags_profile
);
459 static void _check_base_system_content_impl(void)
461 if (_os_xbs_chrooted
&& base_system_content
!= S_UNKNOWN
) {
464 os_assert(base_system_content
== S_UNKNOWN
);
467 const char * path
= BASE_SYSTEM_CONTENT_PATH
;
468 base_system_content
= (access(path
, F_OK
) == 0) ? S_YES
: S_NO
;
471 static bool _check_base_system_content(void)
473 _initialize_status();
475 return status2bool(base_system_content
);
478 static void _check_darwinos_content_impl(void)
480 if (_os_xbs_chrooted
&& darwinos_content
!= S_UNKNOWN
) {
483 os_assert(darwinos_content
== S_UNKNOWN
);
486 const char * path
= DARWINOS_CONTENT_PATH
;
487 darwinos_content
= (access(path
, F_OK
) == 0) ? S_YES
: S_NO
;
490 static bool _check_darwinos_content(void)
492 _initialize_status();
494 return status2bool(darwinos_content
);
499 #if !TARGET_OS_SIMULATOR
500 static void _check_can_has_debugger_impl(void)
502 if (_os_xbs_chrooted
&& can_has_debugger
!= S_UNKNOWN
) {
505 os_assert(can_has_debugger
== S_UNKNOWN
);
509 can_has_debugger
= *((uint32_t *)_COMM_PAGE_DEV_FIRM
) ? S_YES
: S_NO
;
512 * The comm page bit does exist on macOS, but also requires kernel
513 * debugging in the CSR configuration. We don't need to be that strict
516 can_has_debugger
= (csr_check(CSR_ALLOW_APPLE_INTERNAL
) == 0) ? S_YES
: S_NO
;
520 static bool _check_can_has_debugger(void)
522 _initialize_status();
524 return status2bool(can_has_debugger
);
526 #endif // !TARGET_OS_SIMULATOR
528 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
529 static void _check_development_kernel_impl(void)
531 os_assert(development_kernel
== S_UNKNOWN
);
533 * Whitelist values from SUPPORTED_KERNEL_CONFIGS.
535 char *osbuildconfig
= NULL
;
536 size_t osbuildconfig_sz
= 0;
537 errno_t err
= sysctlbyname_get_data_np("kern.osbuildconfig", (void **)&osbuildconfig
, &osbuildconfig_sz
);
539 if (strcmp(osbuildconfig
, "development") == 0 ||
540 strcmp(osbuildconfig
, "debug") == 0 ||
541 strcmp(osbuildconfig
, "profile") == 0 ||
542 strcmp(osbuildconfig
, "kasan") == 0) {
543 development_kernel
= S_YES
;
548 if (development_kernel
== S_UNKNOWN
) {
549 development_kernel
= S_NO
;
553 static bool _check_development_kernel(void)
555 _initialize_status();
557 return status2bool(development_kernel
);
559 #endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
561 static void _check_uses_ephemeral_storage_impl(void)
563 if (_os_xbs_chrooted
&& is_ephemeral
!= S_UNKNOWN
) {
566 os_assert(is_ephemeral
== S_UNKNOWN
);
570 size_t buffer_size
= sizeof(buffer
);
572 sysctlbyname("hw.ephemeral_storage", (void *)&buffer
, &buffer_size
, NULL
, 0);
574 is_ephemeral
= (buffer
!= 0) ? S_YES
: S_NO
;
577 static bool _check_uses_ephemeral_storage(void)
579 _initialize_status();
581 return status2bool(is_ephemeral
);
584 #if !TARGET_OS_SIMULATOR
585 // internal upcall into libtrace
587 _os_trace_basesystem_storage_available(void);
590 _init_has_full_logging(void)
593 if (_check_base_system_content() &&
594 !_os_trace_basesystem_storage_available()) {
595 has_full_logging
= S_NO
;
600 has_full_logging
= S_YES
;
603 static bool _check_has_full_logging(void)
605 _initialize_status();
607 return status2bool(has_full_logging
);
609 #endif // !TARGET_OS_SIMULATOR
611 static void _check_all_statuses(void)
613 #if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
614 _check_internal_content_impl();
617 _check_uses_ephemeral_storage_impl();
619 #if !TARGET_OS_SIMULATOR
620 _check_can_has_debugger_impl();
623 _check_system_version_plist_statuses_impl();
624 _check_development_kernel_impl();
626 _check_internal_diags_profile_impl();
627 _check_factory_content_impl();
628 _check_base_system_content_impl();
629 _check_darwinos_content_impl();
632 #endif // !TARGET_OS_SIMULUATOR
634 _parse_disabled_status(NULL
);
638 os_variant_has_full_logging(const char * __unused subsystem
)
640 #if TARGET_OS_SIMULATOR
643 return _check_has_full_logging();
647 static const variant_check_mapping _variant_map
[] = {
648 {.variant
= "AllowsInternalSecurityPolicies", .function
= os_variant_allows_internal_security_policies
},
649 {.variant
= "HasFactoryContent", .function
= os_variant_has_factory_content
},
650 {.variant
= "HasFullLogging", .function
= os_variant_has_full_logging
},
651 {.variant
= "HasInternalContent", .function
= os_variant_has_internal_content
},
652 {.variant
= "HasInternalDiagnostics", .function
= os_variant_has_internal_diagnostics
},
653 {.variant
= "HasInternalUI", .function
= os_variant_has_internal_ui
},
655 {.variant
= "IsBaseSystem", .function
= os_variant_is_basesystem
},
657 {.variant
= "IsDarwinOS", .function
= os_variant_is_darwinos
},
658 {.variant
= "IsRecovery", .function
= os_variant_is_recovery
},
659 {.variant
= "UsesEphemeralStorage", .function
= os_variant_uses_ephemeral_storage
},
660 {.variant
= NULL
, .function
= NULL
}
664 #ifndef VARIANT_SKIP_EXPORTED
667 os_variant_has_internal_content(const char * __unused subsystem
)
669 if (_check_disabled(VP_CONTENT
)) {
674 return _check_internal_release_type();
676 return _check_internal_content();
682 os_variant_has_internal_diagnostics(const char * __unused subsystem
)
684 if (_check_disabled(VP_DIAGNOSTICS
)) {
689 return _check_internal_release_type();
691 return _check_internal_content() || _check_internal_diags_profile();
696 os_variant_has_internal_ui(const char * __unused subsystem
)
698 if (_check_disabled(VP_UI
)) {
703 return _check_internal_release_type();
705 return _check_internal_content();
710 os_variant_allows_internal_security_policies(const char * __unused subsystem
)
712 if (_check_disabled(VP_SECURITY
)) {
716 #if TARGET_OS_SIMULATOR
717 return _check_internal_content();
718 #elif TARGET_OS_IPHONE
719 return _check_can_has_debugger() || _check_development_kernel();
721 return _check_can_has_debugger();
726 os_variant_has_factory_content(const char * __unused subsystem
)
729 return _check_factory_release_type();
731 return _check_factory_content();
736 os_variant_is_darwinos(const char * __unused subsystem
)
739 return _check_darwin_release_type();
741 return _check_darwinos_content();
746 os_variant_is_recovery(const char * __unused subsystem
)
749 return _check_recovery_release_type();
751 return _check_base_system_content();
757 os_variant_is_basesystem(const char * __unused subsystem
)
759 return _check_base_system_content();
764 os_variant_uses_ephemeral_storage(const char * __unused subsystem
)
766 return _check_uses_ephemeral_storage();
770 os_variant_check(const char *subsystem
, const char *variant
)
772 variant_check_mapping
*current
= (variant_check_mapping
*)_variant_map
;
774 while (current
->variant
) {
775 if (0 == strncasecmp(current
->variant
, variant
, strlen(current
->variant
))) {
776 return current
->function(subsystem
);
785 os_variant_copy_description(const char *subsystem
)
787 variant_check_mapping
*current
= (variant_check_mapping
*)_variant_map
;
790 size_t desc_size
= 0;
791 FILE *outstream
= open_memstream(&desc
, &desc_size
);
797 bool needs_space
= false;
798 while (current
->variant
) {
799 if (current
->function(subsystem
)) {
801 int written
= fputc(' ', outstream
);
802 if (written
== EOF
) {
807 int written
= fputs(current
->variant
, outstream
);
808 if (written
== EOF
) {
817 int closed
= fclose(outstream
);
820 goto close_error_out
;
825 (void)fclose(outstream
);
834 // XXX As an implementation detail, os_boot_mode is piggy-backing on
835 // os_variant's infrastructure. This is not necessarily its long-term home,
836 // particularly after rdar://59966472
838 static enum boot_mode
{
839 BOOTMODE_UNKNOWN
= 0,
843 BOOTMODE_DIAGNOSTICS
,
848 _os_boot_mode_launchd_init(const char *boot_mode
)
850 if (boot_mode
== NULL
) {
851 os_boot_mode
= BOOTMODE_NONE
;
852 } else if (strcmp(boot_mode
, OS_BOOT_MODE_FVUNLOCK
) == 0) {
853 os_boot_mode
= BOOTMODE_FVUNLOCK
;
854 } else if (strcmp(boot_mode
, OS_BOOT_MODE_KCGEN
) == 0) {
855 os_boot_mode
= BOOTMODE_KCGEN
;
856 } else if (strcmp(boot_mode
, OS_BOOT_MODE_DIAGNOSTICS
) == 0) {
857 os_boot_mode
= BOOTMODE_DIAGNOSTICS
;
858 } else if (strcmp(boot_mode
, OS_BOOT_MODE_MIGRATION
) == 0) {
859 os_boot_mode
= BOOTMODE_MIGRATION
;
864 os_boot_mode_query(const char **boot_mode_out
)
866 _initialize_status();
868 switch (os_boot_mode
) {
870 *boot_mode_out
= NULL
;
872 case BOOTMODE_FVUNLOCK
:
873 *boot_mode_out
= OS_BOOT_MODE_FVUNLOCK
;
876 *boot_mode_out
= OS_BOOT_MODE_KCGEN
;
878 case BOOTMODE_DIAGNOSTICS
:
879 *boot_mode_out
= OS_BOOT_MODE_DIAGNOSTICS
;
881 case BOOTMODE_MIGRATION
:
882 *boot_mode_out
= OS_BOOT_MODE_MIGRATION
;
889 #endif // TARGET_OS_OSX
892 os_variant_init_4launchd(const char *boot_mode
)
894 #if TARGET_OS_SIMULATOR
895 os_crash("simulator launchd does not initialize os_variant");
897 os_assert(getpid() == 1);
899 _init_has_full_logging();
902 _os_boot_mode_launchd_init(boot_mode
);
905 // re-initialize disabled status even if we've already initialized
906 // previously, as it's possible we may have initialized before the override
907 // file was available to read
908 _parse_disabled_status(NULL
);
910 uint64_t status
= _get_cached_check_status();
911 size_t status_size
= sizeof(status
);
912 // TODO: assert that this succeeds
913 sysctlbyname(CACHE_SYSCTL_NAME
, NULL
, 0, &status
, status_size
);
917 #endif // VARIANT_SKIP_EXPORTED
920 * Bit allocation in kern.osvariant_status (all ranges inclusive):
921 * - [0-27] are 2-bit check_status values
923 * - [32-32+VP_MAX-1] encode variant_property booleans
924 * - [48-51] encode the boot mode, if known
927 #define STATUS_INITIAL_BITS 0x70000000F0000000ULL
928 #define STATUS_BIT_WIDTH 2
929 #define STATUS_SET 0x2
930 #define STATUS_MASK 0x3
932 enum status_flags_positions
{
933 SFP_INTERNAL_CONTENT
= 0,
934 SFP_CAN_HAS_DEBUGGER
= 1,
935 SFP_INTERNAL_RELEASE_TYPE
= 2,
936 SFP_INTERNAL_DIAGS_PROFILE
= 3,
937 SFP_FACTORY_CONTENT
= 4,
938 SFP_FACTORY_RELEASE_TYPE
= 5,
939 SFP_DARWINOS_RELEASE_TYPE
= 6,
940 SFP_EPHEMERAL_VOLUME
= 7,
941 SFP_RECOVERY_RELEASE_TYPE
= 8,
942 SFP_BASE_SYSTEM_CONTENT
= 9,
943 SFP_DEVELOPMENT_KERNEL
= 10,
944 SFP_DARWINOS_CONTENT
= 11,
945 SFP_FULL_LOGGING
= 12,
948 #define STATUS_BOOT_MODE_SHIFT 48
949 #define STATUS_BOOT_MODE_MASK 0x000F000000000000ULL
951 #if !TARGET_OS_SIMULATOR
952 static uint64_t _get_cached_check_status(void)
954 _initialize_status();
956 uint64_t res
= STATUS_INITIAL_BITS
;
958 #if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
959 os_assert(internal_content
!= S_UNKNOWN
);
960 res
|= internal_content
<< SFP_INTERNAL_CONTENT
* STATUS_BIT_WIDTH
;
963 os_assert(can_has_debugger
!= S_UNKNOWN
);
964 res
|= can_has_debugger
<< SFP_CAN_HAS_DEBUGGER
* STATUS_BIT_WIDTH
;
966 os_assert(is_ephemeral
!= S_UNKNOWN
);
967 res
|= is_ephemeral
<< SFP_EPHEMERAL_VOLUME
* STATUS_BIT_WIDTH
;
969 #ifdef VARIANT_SKIP_EXPORTED
970 // has_full_logging can't be computed outside launchd, so in the tests/etc.
971 // cheat and use the value reported by libdarwin rather than re-computing
972 has_full_logging
= os_variant_check("com.apple.Libc.tests", "HasFullLogging") ?
975 os_assert(has_full_logging
!= S_UNKNOWN
);
977 res
|= has_full_logging
<< SFP_FULL_LOGGING
* STATUS_BIT_WIDTH
;
980 os_assert(internal_release_type
!= S_UNKNOWN
);
981 res
|= internal_release_type
<< SFP_INTERNAL_RELEASE_TYPE
* STATUS_BIT_WIDTH
;
983 os_assert(factory_release_type
!= S_UNKNOWN
);
984 res
|= factory_release_type
<< SFP_FACTORY_RELEASE_TYPE
* STATUS_BIT_WIDTH
;
986 os_assert(darwin_release_type
!= S_UNKNOWN
);
987 res
|= darwin_release_type
<< SFP_DARWINOS_RELEASE_TYPE
* STATUS_BIT_WIDTH
;
989 os_assert(recovery_release_type
!= S_UNKNOWN
);
990 res
|= recovery_release_type
<< SFP_RECOVERY_RELEASE_TYPE
* STATUS_BIT_WIDTH
;
992 os_assert(development_kernel
!= S_UNKNOWN
);
993 res
|= development_kernel
<< SFP_DEVELOPMENT_KERNEL
* STATUS_BIT_WIDTH
;
995 os_assert(internal_diags_profile
!= S_UNKNOWN
);
996 res
|= internal_diags_profile
<< SFP_INTERNAL_DIAGS_PROFILE
* STATUS_BIT_WIDTH
;
998 os_assert(factory_content
!= S_UNKNOWN
);
999 res
|= factory_content
<< SFP_FACTORY_CONTENT
* STATUS_BIT_WIDTH
;
1001 os_assert(base_system_content
!= S_UNKNOWN
);
1002 res
|= base_system_content
<< SFP_BASE_SYSTEM_CONTENT
* STATUS_BIT_WIDTH
;
1004 os_assert(darwinos_content
!= S_UNKNOWN
);
1005 res
|= darwinos_content
<< SFP_DARWINOS_CONTENT
* STATUS_BIT_WIDTH
;
1008 for (int i
= 0; i
< VP_MAX
; i
++) {
1009 if (disabled_status
[i
]) {
1010 res
|= 0x1ULL
<< (i
+ 32);
1014 #if !defined(VARIANT_SKIP_EXPORTED) && TARGET_OS_OSX
1015 res
|= ((uint64_t)os_boot_mode
) << STATUS_BOOT_MODE_SHIFT
;
1016 #endif // TARGET_OS_OSX
1021 static void _restore_cached_check_status(uint64_t status
)
1023 #if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
1024 if ((status
>> (SFP_INTERNAL_CONTENT
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1025 internal_content
= (status
>> (SFP_INTERNAL_CONTENT
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1028 if ((status
>> (SFP_CAN_HAS_DEBUGGER
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1029 can_has_debugger
= (status
>> (SFP_CAN_HAS_DEBUGGER
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1031 if ((status
>> (SFP_EPHEMERAL_VOLUME
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1032 is_ephemeral
= (status
>> (SFP_EPHEMERAL_VOLUME
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1034 if ((status
>> (SFP_FULL_LOGGING
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1035 has_full_logging
= (status
>> (SFP_FULL_LOGGING
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1037 #if TARGET_OS_IPHONE
1038 if ((status
>> (SFP_INTERNAL_RELEASE_TYPE
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1039 internal_release_type
= (status
>> (SFP_INTERNAL_RELEASE_TYPE
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1041 if ((status
>> (SFP_FACTORY_RELEASE_TYPE
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1042 factory_release_type
= (status
>> (SFP_FACTORY_RELEASE_TYPE
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1044 if ((status
>> (SFP_DARWINOS_RELEASE_TYPE
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1045 darwin_release_type
= (status
>> (SFP_DARWINOS_RELEASE_TYPE
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1047 if ((status
>> (SFP_RECOVERY_RELEASE_TYPE
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1048 recovery_release_type
= (status
>> (SFP_RECOVERY_RELEASE_TYPE
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1050 if ((status
>> (SFP_DEVELOPMENT_KERNEL
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1051 development_kernel
= (status
>> (SFP_DEVELOPMENT_KERNEL
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1053 if ((status
>> (SFP_INTERNAL_DIAGS_PROFILE
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1054 internal_diags_profile
= (status
>> (SFP_INTERNAL_DIAGS_PROFILE
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1056 if ((status
>> (SFP_FACTORY_CONTENT
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1057 factory_content
= (status
>> (SFP_FACTORY_CONTENT
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1059 if ((status
>> (SFP_BASE_SYSTEM_CONTENT
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1060 base_system_content
= (status
>> (SFP_BASE_SYSTEM_CONTENT
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1062 if ((status
>> (SFP_DARWINOS_CONTENT
* STATUS_BIT_WIDTH
)) & STATUS_SET
)
1063 darwinos_content
= (status
>> (SFP_DARWINOS_CONTENT
* STATUS_BIT_WIDTH
)) & STATUS_MASK
;
1066 for (int i
= 0; i
< VP_MAX
; i
++) {
1067 disabled_status
[i
] = (status
>> (32 + i
)) & 0x1;
1070 #if !defined(VARIANT_SKIP_EXPORTED) && TARGET_OS_OSX
1071 os_boot_mode
= (enum boot_mode
)((status
& STATUS_BOOT_MODE_MASK
) >> STATUS_BOOT_MODE_SHIFT
);
1072 #endif // TARGET_OS_OSX
1074 #endif // !TARGET_OS_SIMULATOR