+static bool
+is_disk_device(const char *pathname) {
+ bool is_disk_dev = false;
+
+ if (strncmp(pathname, "/dev/disk", strlen("/dev/disk")) == 0) {
+ is_disk_dev = true;
+ } else if (strncmp(pathname, "/dev/rdisk", strlen("/dev/rdisk")) == 0) {
+ is_disk_dev = true;
+ }
+
+ return (is_disk_dev);
+}
+
+static int
+query_disk_info(int fd, char *uuid_str, int uuid_len, bool *is_internal) {
+ io_service_t obj;
+ io_iterator_t iter;
+ kern_return_t error;
+ CFBooleanRef removableRef;
+ CFStringRef uuidRef;
+ CFStringRef locationRef;
+ CFDictionaryRef protocolCharacteristics;
+ bool deviceInternal, mediaRemovable;
+ int result;
+ char disk_path[PATH_MAX];
+ char *disk_name;
+
+ result = EINVAL;
+ deviceInternal = false;
+ mediaRemovable = false;
+ removableRef = NULL;
+ protocolCharacteristics = NULL;
+ uuidRef = NULL;
+ obj = IO_OBJECT_NULL;
+ iter = IO_OBJECT_NULL;
+
+ // Fetch the path
+ if (fcntl(fd, F_GETPATH, disk_path) == -1) {
+ goto out;
+ }
+
+ // Make sure path begins with /dev/disk or /dev/rdisk
+ if (is_disk_device(disk_path) == false) {
+ goto out;
+ }
+
+ // Derive device name
+ disk_name = disk_path;
+ if(strncmp(disk_path, _PATH_DEV, strlen(_PATH_DEV)) == 0) {
+ // Skip over leading "/dev/"
+ disk_name += strlen(_PATH_DEV);
+ }
+ if (strncmp(disk_name, "r", strlen("r")) == 0) {
+ // Raw device, skip over leading "r"
+ disk_name += strlen("r");
+ }
+
+ // Get an iterator object
+ error = IOServiceGetMatchingServices(kIOMasterPortDefault,
+ IOBSDNameMatching(kIOMasterPortDefault, 0, disk_name), &iter);
+ if (error) {
+ os_log_error(OS_LOG_DEFAULT, "Warning, unable to obtain UUID info (iterator), device %s", disk_name);
+ goto out;
+ }
+
+ // Get the matching device object
+ obj = IOIteratorNext(iter);
+ if (!obj) {
+ os_log_error(OS_LOG_DEFAULT, "Warning, unable to obtain UUID info (dev obj), device %s", disk_name);
+ goto out;
+ }
+
+ // Get a protocol characteristics dictionary
+ protocolCharacteristics = (CFDictionaryRef) IORegistryEntrySearchCFProperty(obj,
+ kIOServicePlane,
+ CFSTR(kIOPropertyProtocolCharacteristicsKey),
+ kCFAllocatorDefault,
+ kIORegistryIterateRecursively|kIORegistryIterateParents);
+
+ if ((protocolCharacteristics == NULL) || (CFDictionaryGetTypeID() != CFGetTypeID(protocolCharacteristics)))
+ {
+ os_log_error(OS_LOG_DEFAULT, "Warning, failed to obtain UUID info (protocol characteristics), device %s\n", disk_name);
+ goto out;
+ }
+
+ // Check for kIOPropertyInternalKey
+ locationRef = (CFStringRef) CFDictionaryGetValue(protocolCharacteristics, CFSTR(kIOPropertyPhysicalInterconnectLocationKey));
+
+ if ((locationRef == NULL) || (CFStringGetTypeID() != CFGetTypeID(locationRef))) {
+ os_log_error(OS_LOG_DEFAULT, "Warning, failed to obtain UUID info (location), device %s\n", disk_name);
+ goto out;
+ }
+
+ if (CFEqual(locationRef, CFSTR(kIOPropertyInternalKey))) {
+ deviceInternal = true;
+ }
+
+ // Check for kIOMediaRemovableKey
+ removableRef = (CFBooleanRef)IORegistryEntrySearchCFProperty(obj,
+ kIOServicePlane,
+ CFSTR(kIOMediaRemovableKey),
+ kCFAllocatorDefault,
+ 0);
+
+ if ((removableRef == NULL) || (CFBooleanGetTypeID() != CFGetTypeID(removableRef))) {
+ os_log_error(OS_LOG_DEFAULT, "Warning, unable to obtain UUID info (MediaRemovable key), device %s", disk_name);
+ goto out;
+ }
+
+ if (CFBooleanGetValue(removableRef)) {
+ mediaRemovable = true;
+ }
+
+ // is_internal ==> DeviceInternal && !MediaRemovable
+ if ((deviceInternal == true) && (mediaRemovable == false)) {
+ *is_internal = true;
+ } else {
+ *is_internal = false;
+ }
+
+ // Get the UUID
+ uuidRef = (CFStringRef)IORegistryEntrySearchCFProperty(obj,
+ kIOServicePlane,
+ CFSTR(kIOMediaUUIDKey),
+ kCFAllocatorDefault,
+ 0);
+ if ((uuidRef == NULL) || (CFStringGetTypeID() != CFGetTypeID(uuidRef)))
+ {
+ os_log_error(OS_LOG_DEFAULT, "Warning, unable to obtain UUID info (MediaUUID key), device %s", disk_name);
+ goto out;
+ }
+
+ if (!CFStringGetCString(uuidRef, uuid_str, uuid_len, kCFStringEncodingASCII)) {
+ os_log_error(OS_LOG_DEFAULT, "Warning, unable to obtain UUID info (convert UUID), device %s", disk_name);
+ goto out;
+ }
+
+ // Success
+ result = 0;
+
+out:
+ if (obj != IO_OBJECT_NULL) {
+ IOObjectRelease(obj);
+ }
+ if (iter != IO_OBJECT_NULL) {
+ IOObjectRelease(iter);
+ }
+ if (removableRef != NULL) {
+ CFRelease(removableRef);
+ }
+ if (protocolCharacteristics != NULL) {
+ CFRelease(protocolCharacteristics);
+ }
+ if (uuidRef != NULL) {
+ CFRelease(uuidRef);
+ }
+
+ return (result);
+}
+
+static
+int run_xartutil(uuid_string_t uuid_str, bool is_internal)
+{
+ char external[2];
+ pid_t child_pid, wait_pid;
+ posix_spawn_file_actions_t fileActions;
+ bool haveFileActions = false;
+ int child_status = 0;
+ int result = 0;
+
+ char arg1[] = "xartutil";
+ char arg2[] = "--erase";
+ char arg4[] = "--is-external";
+
+ external[0] = (is_internal == false) ? '1' : '0';
+ external[1] = 0;
+
+ char *xartutil_argv[] = {arg1, arg2, uuid_str, arg4, external, NULL};
+
+ result = posix_spawn_file_actions_init(&fileActions);
+ if (result) {
+ os_log_error(OS_LOG_DEFAULT, "Warning, init xartutil file actions error: %d", result);
+ result = -1;
+ goto out;
+ }
+
+ haveFileActions = true;
+
+ // Redirect stdout & stderr (results not critical, so we ignore return values).
+ posix_spawn_file_actions_addopen(&fileActions, STDOUT_FILENO, "/dev/null", O_WRONLY, 0);
+ posix_spawn_file_actions_addopen(&fileActions, STDERR_FILENO, "/dev/null", O_WRONLY, 0);
+
+ result = posix_spawn(&child_pid, "/usr/sbin/xartutil", &fileActions, NULL, xartutil_argv, NULL);
+
+ if (result) {
+ os_log_error(OS_LOG_DEFAULT, "Warning, unable to start xartutil, spawn error: %d", result);
+ result = -1;
+ goto out;
+ }
+
+ do {
+ wait_pid = waitpid(child_pid, &child_status, 0);
+ } while (wait_pid == -1 && errno == EINTR);
+
+ if (wait_pid == -1) {
+ os_log_error(OS_LOG_DEFAULT, "Warning, unable to start xartutil, waitpid error: %d", errno);
+ result = -1;
+ goto out;
+ }
+
+ if (WIFEXITED(child_status)) {
+ // xartutil terminated normally, get exit status
+ result = WEXITSTATUS(child_status);
+
+ if (result) {
+ os_log_error(OS_LOG_DEFAULT, "Warning, xartutil returned status %d", result);
+ }
+ } else {
+ result = -1;
+
+ if (WIFSIGNALED(child_status)) {
+ os_log_error(OS_LOG_DEFAULT, "Warning, xartutil terminated by signal: %u", WTERMSIG(child_status));
+ } else if (WIFSTOPPED(child_status)) {
+ os_log_error(OS_LOG_DEFAULT, "Warning, xartutil stopped by signal: %u", WSTOPSIG(child_status));
+ } else {
+ os_log_error(OS_LOG_DEFAULT, "Warning, xartutil terminated abnormally, status 0x%x", child_status);
+ }
+ }
+
+out:
+
+ if (haveFileActions) {
+ posix_spawn_file_actions_destroy(&fileActions);
+ }
+
+ return (result);
+}
+