summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2022-01-18 00:09:36 +0100
committerCarl Hetherington <cth@carlh.net>2022-01-19 20:39:34 +0100
commit9b9202c7f9fc26fcef0984189aaed366b7c6d726 (patch)
tree66653eea92abc8d7f5e551b6336145331bc9190c
parent59bb9538218eee564ab3c07f923628e0a47bf207 (diff)
Adjust how macOS drives are analysed and add a couple of tests.
-rw-r--r--src/lib/cross.h10
-rw-r--r--src/lib/cross_common.cc68
-rw-r--r--src/lib/cross_osx.cc18
-rw-r--r--test/disk_writer_test.cc78
4 files changed, 125 insertions, 49 deletions
diff --git a/src/lib/cross.h b/src/lib/cross.h
index ac1f028f4..aad223d60 100644
--- a/src/lib/cross.h
+++ b/src/lib/cross.h
@@ -142,19 +142,17 @@ void disk_write_finished ();
struct OSXMediaPath
{
- bool real; ///< true for a "real" disk, false for a synthesized APFS one
- std::string prt; ///< "PRT" entry from the media path
+ bool real; ///< true for a "real" disk, false for a synthesized APFS one
+ std::vector<std::string> parts; ///< parts of the media path after the :
};
-
struct OSXDisk
{
- std::string mount_point;
+ std::string device;
boost::optional<std::string> vendor;
boost::optional<std::string> model;
- bool real;
- std::string prt;
+ OSXMediaPath media_path;
bool whole;
std::vector<boost::filesystem::path> mount_points;
unsigned long size;
diff --git a/src/lib/cross_common.cc b/src/lib/cross_common.cc
index 250db3cd5..bc1a54367 100644
--- a/src/lib/cross_common.cc
+++ b/src/lib/cross_common.cc
@@ -124,8 +124,6 @@ Drive::log_summary () const
optional<OSXMediaPath>
analyse_osx_media_path (string path)
{
- using namespace boost::algorithm;
-
if (path.find("/IOHDIXController") != string::npos) {
/* This is a disk image, so we completely ignore it */
LOG_DISK_NC("Ignoring this as it seems to be a disk image");
@@ -133,27 +131,32 @@ analyse_osx_media_path (string path)
}
OSXMediaPath mp;
- if (starts_with(path, "IODeviceTree:")) {
+ vector<string> parts;
+ split(parts, path, boost::is_any_of("/"));
+ std::copy(parts.begin() + 1, parts.end(), back_inserter(mp.parts));
+
+ if (!parts.empty() && parts[0] == "IODeviceTree:") {
mp.real = true;
- } else if (starts_with(path, "IOService:")) {
+ if (mp.parts.size() < 2) {
+ /* Later we expect at least 2 parts in a IODeviceTree */
+ LOG_DISK_NC("Ignoring this as it has a strange media path");
+ return {};
+ }
+ } else if (!parts.empty() && parts[0] == "IOService:") {
mp.real = false;
} else {
return {};
}
- vector<string> bits;
- split(bits, path, boost::is_any_of("/"));
- for (auto i: bits) {
- if (starts_with(i, "PRT")) {
- mp.prt = i;
- }
- }
-
return mp;
}
-/* This is in _common so we can use it in unit tests */
+/* Take soem OSXDisk objects, representing disks that `DARegisterDiskAppearedCallback` told us about,
+ * and find those drives that we could write a DCP to. The drives returned are "real" (not synthesized)
+ * and are whole disks (not partitions). They may be mounted, or contain mounted partitions, in which
+ * their mounted() method will return true.
+ */
vector<Drive>
osx_disks_to_drives (vector<OSXDisk> disks)
{
@@ -165,38 +168,37 @@ osx_disks_to_drives (vector<OSXDisk> disks)
continue;
}
for (auto& j: disks) {
- if (!j.mount_points.empty() && starts_with(j.mount_point, i.mount_point)) {
- LOG_DISK("Marking %1 as mounted because %2 is", i.mount_point, j.mount_point);
+ if (!j.mount_points.empty() && starts_with(j.device, i.device)) {
+ LOG_DISK("Marking %1 as mounted because %2 is", i.device, j.device);
std::copy(j.mount_points.begin(), j.mount_points.end(), back_inserter(i.mount_points));
}
}
}
- /* Make a map of the PRT codes and mount points of mounted, synthesized disks */
- map<string, vector<boost::filesystem::path>> mounted_synths;
- for (auto const& i: disks) {
- if (!i.real && !i.mount_points.empty()) {
- LOG_DISK("Found a mounted synth %1 with %2", i.mount_point, i.prt);
- mounted_synths[i.prt] = i.mount_points;
- }
- }
-
- /* Mark containers of those mounted synths as themselves mounted */
+ /* Mark containers of mounted synths as themselves mounted */
for (auto& i: disks) {
- if (i.real) {
- auto j = mounted_synths.find(i.prt);
- if (j != mounted_synths.end()) {
- LOG_DISK("Marking %1 (%2) as mounted because it contains a mounted synth", i.mount_point, i.prt);
- std::copy(j->second.begin(), j->second.end(), back_inserter(i.mount_points));
+ if (i.media_path.real) {
+ for (auto& j: disks) {
+ if (!j.media_path.real && !j.mount_points.empty()) {
+ /* i is real, j is a mounted synth; if we see the first two parts
+ * of i anywhere in j we assume they are related and so i shares
+ * j's mount points.
+ */
+ if (
+ find(j.media_path.parts.begin(), j.media_path.parts.end(), i.media_path.parts[0]) != j.media_path.parts.end() &&
+ find(j.media_path.parts.begin(), j.media_path.parts.end(), i.media_path.parts[1]) != j.media_path.parts.end()) {
+ LOG_DISK("Marking %1 as mounted because %2 is (found %3 and %4)", i.device, j.device, i.media_path.parts[0], i.media_path.parts[1]);
+ std::copy(j.mount_points.begin(), j.mount_points.end(), back_inserter(i.mount_points));
+ }
+ }
}
}
}
vector<Drive> drives;
for (auto const& i: disks) {
- if (i.whole) {
- /* A whole disk that is not a container for a mounted synth */
- drives.push_back(Drive(i.mount_point, i.mount_points, i.size, i.vendor, i.model));
+ if (i.whole && i.media_path.real) {
+ drives.push_back(Drive(i.device, i.mount_points, i.size, i.vendor, i.model));
LOG_DISK_NC(drives.back().log_summary());
}
}
diff --git a/src/lib/cross_osx.cc b/src/lib/cross_osx.cc
index 018516abb..2dc9b2702 100644
--- a/src/lib/cross_osx.cc
+++ b/src/lib/cross_osx.cc
@@ -380,8 +380,8 @@ mount_point (CFDictionaryRef& description)
* a partition /dev/disk2s2 whose content is made into a synthesized /dev/disk3, itself containing some partitions
* which are mounted. /dev/disk2s2 is not considered to be mounted, in this case. So we need to know that
* disk2s2 is related to disk3 so we can consider disk2s2 as mounted if any parts of disk3 are. In order to do
- * this I am picking out what looks like a suitable identifier prefixed with PRT from the MediaContentKey.
- * If disk2s2 and disk3 have the same PRT code I am assuming they are linked.
+ * this I am taking the first two parts of the IODeviceTree and seeing if they exist anywhere in a
+ * IOService identifier. If they do, I am assuming the IOService device is on the matching IODeviceTree device.
*
* Lots of this is guesswork and may be broken. In my defence the documentation that I have been able to
* unearth is, to put it impolitely, crap.
@@ -399,8 +399,8 @@ disk_appeared (DADiskRef disk, void* context)
OSXDisk this_disk;
- this_disk.mount_point = string("/dev/") + bsd_name;
- LOG_DISK("Mount point is %1", this_disk.mount_point);
+ this_disk.device = string("/dev/") + bsd_name;
+ LOG_DISK("Device is %1", this_disk.device);
CFDictionaryRef description = DADiskCopyDescription (disk);
@@ -414,8 +414,7 @@ disk_appeared (DADiskRef disk, void* context)
return;
}
- this_disk.real = media_path->real;
- this_disk.prt = media_path->prt;
+ this_disk.media_path = *media_path;
this_disk.whole = is_whole_drive (disk);
auto mp = mount_point (description);
if (mp) {
@@ -423,11 +422,10 @@ disk_appeared (DADiskRef disk, void* context)
}
LOG_DISK(
- "%1 prt=%2 %3 %4",
- this_disk.real ? "Real" : "Synth",
- this_disk.prt,
+ "%1 %2 mounted at %3",
+ this_disk.media_path.real ? "Real" : "Synth",
this_disk.whole ? "whole" : "part",
- mp ? ("mounted at " + mp->string()) : "unmounted"
+ mp ? mp->string() : "[nowhere]"
);
auto media_size_cstr = CFDictionaryGetValue (description, kDADiskDescriptionMediaSizeKey);
diff --git a/test/disk_writer_test.cc b/test/disk_writer_test.cc
index 60d7fe22a..9e5f88b80 100644
--- a/test/disk_writer_test.cc
+++ b/test/disk_writer_test.cc
@@ -138,3 +138,81 @@ BOOST_AUTO_TEST_CASE (disk_writer_test1)
check_file ("build/test/disk_writer_test1/foo", "build/test/disk_writer_test1_foo_back");
}
+
+BOOST_AUTO_TEST_CASE (osx_drive_identification_test)
+{
+ vector<OSXDisk> disks;
+
+ auto disk = [&disks](string mount_point, string media_path, bool whole, std::vector<boost::filesystem::path> mount_points)
+ {
+ auto mp = analyse_osx_media_path (media_path);
+ if (mp) {
+ disks.push_back({mount_point, {}, {}, *mp, whole, mount_points, 0});
+ }
+ };
+
+ auto find_unmounted = [](vector<OSXDisk> disks) {
+ auto drives = osx_disks_to_drives (disks);
+ vector<Drive> unmounted;
+ std::copy_if (drives.begin(), drives.end(), std::back_inserter(unmounted), [](Drive const& drive) { return !drive.mounted(); });
+ return unmounted;
+ };
+
+ disk("/dev/disk4s1", "IODeviceTree:/arm-io@10F00000/apcie@90000000/pci-bridge1@1/pcie-xhci@0/@7:1", false, {});
+ disk("/dev/disk4", "IODeviceTree:/arm-io@10F00000/apcie@90000000/pci-bridge1@1/pcie-xhci@0/@7:0", true, {});
+ disk("/dev/disk0", "IODeviceTree:/arm-io@10F00000/ans@77400000/iop-ans-nub/AppleANS3NVMeController/@1:0", true, {});
+ disk("/dev/disk0s1", "IODeviceTree:/arm-io@10F00000/ans@77400000/iop-ans-nub/AppleANS3NVMeController/@1:1", false, {});
+ disk("/dev/disk0s2", "IODeviceTree:/arm-io@10F00000/ans@77400000/iop-ans-nub/AppleANS3NVMeController/@1:2", false, {});
+ disk("/dev/disk0s3", "IODeviceTree:/arm-io@10F00000/ans@77400000/iop-ans-nub/AppleANS3NVMeController/@1:3", false, {});
+ disk("/dev/disk1", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/ APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/iBootSystemContainer@1/AppleAPFSContainerScheme/AppleAPFSMedia", true, {});
+ disk("/dev/disk2", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/RecoveryOSContainer@3/AppleAPFSContainerScheme/AppleAPFSMedia", true, {});
+ disk("/dev/disk3", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia", false, {});
+ disk("/dev/disk1s1", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/iBootSystemContainer@1/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/iSCPreboot@1", false, {});
+ disk("/dev/disk1s2", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/iBootSystemContainer@1/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/xART@2", false, {});
+ disk("/dev/disk1s3", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/iBootSystemContainer@1/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Hardware@3", false, {});
+ disk("/dev/disk1s4", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/iBootSystemContainer@1/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Recovery@4", false, {});
+ disk("/dev/disk2s1", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/RecoveryOSContainer@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Recovery@1", false, {});
+ disk("/dev/disk2s2", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/RecoveryOSContainer@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Update@2", false, {});
+ disk("/dev/disk3s1", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Macintosh HD@1", false, {});
+ disk("/dev/disk3s4", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Update@4", false, {"/System/Volumes/Update"});
+ disk("/dev/disk3s5", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Data@5", false, {"/System/Volumes/Data"});
+ disk("/dev/disk3s2", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Preboot@2", false, {"/System/Volumes/Preboot"});
+ disk("/dev/disk3s3", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Recovery@3", false, {});
+ disk("/dev/disk3s6", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/VM@6", false, {"/System/Volumes/VM"});
+ disk("/dev/disk3s1s1", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Macintosh HD@1/com.apple.os.update-EA882DCA7A28EBA0A6E94689836BB10D77D84D1AEE2468E17775A447AA815278@1", false, {"/"});
+
+ vector<Drive> writeable = find_unmounted (disks);
+ BOOST_REQUIRE_EQUAL (writeable.size(), 1U);
+ BOOST_CHECK_EQUAL (writeable[0].device(), "/dev/disk4");
+
+ disks.clear ();
+ disk("/dev/disk4s1", "IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@0/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media/IOGUIDPartitionScheme/disk image@1", false, {});
+ disk("/dev/disk4", "IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@0/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media", true, {});
+ disk("/dev/disk3s1", "IODeviceTree:/PCI0@0/XHC1@14/@2:1", false, {});
+ disk("/dev/disk3", "IODeviceTree:/PCI0@0/XHC1@14/@2:0", true, {});
+ disk("/dev/disk0", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:0", true, {});
+ disk("/dev/disk0s1", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:1", false, {});
+ disk("/dev/disk0s2", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:2", false, {"/Volumes/Macintosh HD"});
+ disk("/dev/disk0s3", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:3", false, {});
+ disk("/dev/disk0s4", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:4", false, {});
+ disk("/dev/disk0s5", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:5", false, {"/Volumes/High Sierra"});
+ disk("/dev/disk0s6", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:6", false, {});
+ disk("/dev/disk0s7", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:7", false, {"/Volumes/Recovery HD"});
+ disk("/dev/disk1", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia", true, {});
+ disk("/dev/disk", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia", true, {});
+ disk("/dev/disk1s1", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Untitled - Data@1", false, {"/Volumes/Untitled - Data"});
+ disk("/dev/disk1s2", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Preboot@2", false, {});
+ disk("/dev/disk1s3", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Recovery@3", false, {});
+ disk("/dev/disk1s4", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/VM@4", false, {});
+ disk("/dev/disk1s5", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Untitled@5", false, {"/Volumes/Untitled"});
+ disk("/dev/disk2s1", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Catalina - Data@1", false, {});
+ disk("/dev/disk2s2", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Preboot@2", false, {});
+ disk("/dev/disk2s3", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Recovery@3", false, {});
+ disk("/dev/disk2s4", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/VM@4", false, {"/private/var/vm"});
+ disk("/dev/disk2s5", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Catalina@5", false, {"/"});
+
+ writeable = find_unmounted (disks);
+ BOOST_REQUIRE_EQUAL (writeable.size(), 1U);
+ BOOST_CHECK_EQUAL (writeable[0].device(), "/dev/disk3");
+}
+