/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
+ 7259A9731D519322008F83F6 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7259A9721D519322008F83F6 /* IOKit.framework */; };
+ 7259A9751D51932B008F83F6 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7259A9741D51932B008F83F6 /* CoreFoundation.framework */; };
BA79F9CB13BB7207006A292D /* ExtentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BA79F9A313BB70FF006A292D /* ExtentManager.cpp */; };
BA79F9CC13BB7207006A292D /* getmntopts.c in Sources */ = {isa = PBXBuildFile; fileRef = BA79F9A613BB70FF006A292D /* getmntopts.c */; };
BA79F9CD13BB7207006A292D /* humanize_number.c in Sources */ = {isa = PBXBuildFile; fileRef = BA79F9A813BB70FF006A292D /* humanize_number.c */; };
BA79F9DB13BB7698006A292D /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = "/usr/local/share/man/man3";
+ dstPath = /usr/local/share/man/man3;
dstSubfolderSpec = 0;
files = (
BA79F9DD13BB76B0006A292D /* getmntopts.3 in CopyFiles */,
BA79F9E713BB77BB006A292D /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = "/usr/local/OpenSourceVersions";
+ dstPath = /usr/local/OpenSourceVersions;
dstSubfolderSpec = 0;
files = (
BA79F9E913BB77FA006A292D /* libutil.plist in CopyFiles */,
BA79F9E813BB77D6006A292D /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = "/usr/local/OpenSourceLicenses";
+ dstPath = /usr/local/OpenSourceLicenses;
dstSubfolderSpec = 0;
files = (
BA79F9EA13BB77FF006A292D /* libutil.txt in CopyFiles */,
FDBC26EE1741B13400CA4B2B /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
- dstPath = "/System/Library/LaunchDaemons";
+ dstPath = /System/Library/LaunchDaemons;
dstSubfolderSpec = 0;
files = (
FDBC27051741B1C300CA4B2B /* com.apple.tzlinkd.plist in CopyFiles */,
/* Begin PBXFileReference section */
3F09C378186D1F73007AF93C /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = base.xcconfig; path = xcconfigs/base.xcconfig; sourceTree = "<group>"; };
+ 7259A9721D519322008F83F6 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
+ 7259A9741D51932B008F83F6 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
BA79F9A313BB70FF006A292D /* ExtentManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ExtentManager.cpp; sourceTree = "<group>"; };
BA79F9A413BB70FF006A292D /* ExtentManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExtentManager.h; sourceTree = "<group>"; };
BA79F9A513BB70FF006A292D /* getmntopts.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = getmntopts.3; sourceTree = "<group>"; };
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 7259A9751D51932B008F83F6 /* CoreFoundation.framework in Frameworks */,
+ 7259A9731D519322008F83F6 /* IOKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 7259A9711D519321008F83F6 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 7259A9741D51932B008F83F6 /* CoreFoundation.framework */,
+ 7259A9721D519322008F83F6 /* IOKit.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
BA79F99513BB70D7006A292D = {
isa = PBXGroup;
children = (
BA79F9BE13BB70FF006A292D /* wipefs.h */,
FDBC270C1741B66500CA4B2B /* xcconfigs */,
BA79F9C613BB718B006A292D /* Products */,
+ 7259A9711D519321008F83F6 /* Frameworks */,
);
sourceTree = "<group>";
};
#include <sys/ioctl.h>
#include <sys/disk.h>
#include <sys/stat.h>
+#include <sys/syslimits.h>
+#include <uuid/uuid.h>
+#include <paths.h>
+#include <string.h>
+#include <spawn.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
+#include <CoreFoundation/CFNumber.h>
+#include <os/log.h>
#include "ExtentManager.h"
#include "wipefs.h"
-#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+#define wipefs_roundup(x, y) ((((x)+((y)-1))/(y))*(y))
struct __wipefs_ctx {
int fd;
class ExtentManager extMan;
+
+ // xartutil information
+ bool have_xartutil_info;
+ uuid_string_t uuid_str;
+ bool is_internal;
};
static void
extMan->AddByteRangeExtent(extMan->totalBytes - 512, 512);
}
+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);
+}
+
extern "C" int
wipefs_alloc(int fd, size_t block_size, wipefs_ctx *handle)
{
off_t totalSizeInBytes = 0;
class ExtentManager *extMan = NULL;
struct stat sbuf = { 0 };
+ bool have_xartutil_info = false;
+ uuid_string_t uuid_str;
+ bool is_internal;
+ int uuid_err = 0;
*handle = NULL;
+ uuid_str[0] = 0;
(void)fstat(fd, &sbuf);
switch (sbuf.st_mode & S_IFMT) {
case S_IFCHR:
goto labelExit;
}
totalSizeInBytes = numBlocks * nativeBlockSize;
+
+ uuid_err = query_disk_info(fd, uuid_str, sizeof(uuid_str), &is_internal);
+ if (uuid_err == 0) {
+ have_xartutil_info = true;
+ }
break;
case S_IFREG:
nativeBlockSize = sbuf.st_blksize;
AddExtentsForZFS(extMan);
AddExtentsForPartitions(extMan);
AddExtentsForCoreStorage(extMan);
+
+ (*handle)->have_xartutil_info = false;
+
+ if (have_xartutil_info == true) {
+ (*handle)->have_xartutil_info = true;
+ (*handle)->is_internal = is_internal;
+ memcpy((*handle)->uuid_str, uuid_str, sizeof(uuid_str));
+ }
}
catch (bad_alloc &e) {
err = ENOMEM;
size_t bufSize;
dk_extent_t extent;
dk_unmap_t unmap;
+ bool did_write = false;
memset(&extent, 0, sizeof(dk_extent_t));
extent.length = handle->extMan.totalBytes;
size_t nativeBlockSize = handle->extMan.nativeBlockSize;
off_t newOffset, newEndOffset;
newOffset = byteOffset / nativeBlockSize * nativeBlockSize;
- newEndOffset = roundup(byteOffset + numBytes, nativeBlockSize);
+ newEndOffset = wipefs_roundup(byteOffset + numBytes, nativeBlockSize);
byteOffset = newOffset;
numBytes = newEndOffset - newOffset;
}
}
numBytes -= numBytesToWrite;
byteOffset += numBytesToWrite;
+
+ if (did_write == false) {
+ did_write = true;
+ }
}
- }
+ }
labelExit:
(void)ioctl(handle->fd, DKIOCSYNCHRONIZECACHE);
if (bufZero != NULL)
delete[] bufZero;
+
+ if ((did_write == true) && (handle->have_xartutil_info == true)) {
+ // We wrote some zero bytes and have UUID info, notify xART now.
+ run_xartutil(handle->uuid_str, handle->is_internal);
+ }
+
return err;
} // wipefs_wipe