Skip to content

Commit

Permalink
VDev Disk Arbitration metadata
Browse files Browse the repository at this point in the history
Also provide disk metadata from DiskArbitration, with code copied from
InvariantDisks. The the new information, as well as the original data from
ZFS is copied to the PasteBoard when selecting the menu.
  • Loading branch information
cbreak-black committed Jun 9, 2019
1 parent 38945db commit 34be689
Show file tree
Hide file tree
Showing 4 changed files with 365 additions and 25 deletions.
10 changes: 10 additions & 0 deletions ZetaWatch.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
7018765C20E7DA8100BA39B8 /* libzpool.1.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7018765A20E7DA8100BA39B8 /* libzpool.1.dylib */; };
7018765D20E7DA9900BA39B8 /* libzpool.1.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7018765A20E7DA8100BA39B8 /* libzpool.1.dylib */; };
7018765E20E7DA9900BA39B8 /* libzpool.1.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7018765A20E7DA8100BA39B8 /* libzpool.1.dylib */; };
70703F3722AD7633002C760A /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70703F3622AD7633002C760A /* DiskArbitration.framework */; };
70703F3922AD7A17002C760A /* IDDiskArbitrationUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70703F3822AD7A16002C760A /* IDDiskArbitrationUtils.cpp */; };
709C1CAD1C354F8B00929DAE /* ZetaPoolWatcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 709C1CAC1C354F8B00929DAE /* ZetaPoolWatcher.mm */; };
70AE5AB222A3DBAA002C760A /* ZetaImportMenuDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70AE5AB122A3DBAA002C760A /* ZetaImportMenuDelegate.mm */; };
70AE5AB522A3F7D3002C760A /* ZetaBaseDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 70AE5AB422A3F7D3002C760A /* ZetaBaseDelegate.m */; };
Expand Down Expand Up @@ -116,8 +118,11 @@
7006C4AD1C26D3FA00929DAE /* ZetaMenuDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZetaMenuDelegate.h; sourceTree = "<group>"; };
7018763D20E7B44800BA39B8 /* libZFSWrapperStatic.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libZFSWrapperStatic.a; sourceTree = BUILT_PRODUCTS_DIR; };
7018765A20E7DA8100BA39B8 /* libzpool.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libzpool.1.dylib; sourceTree = "<group>"; };
70703F3622AD7633002C760A /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = System/Library/Frameworks/DiskArbitration.framework; sourceTree = SDKROOT; };
70703F3822AD7A16002C760A /* IDDiskArbitrationUtils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IDDiskArbitrationUtils.cpp; sourceTree = "<group>"; };
709C1CAC1C354F8B00929DAE /* ZetaPoolWatcher.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ZetaPoolWatcher.mm; sourceTree = "<group>"; };
709C1CAE1C354F9B00929DAE /* ZetaPoolWatcher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZetaPoolWatcher.h; sourceTree = "<group>"; };
70A60A4622AD7A5F002C760A /* IDDiskArbitrationUtils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = IDDiskArbitrationUtils.hpp; path = InvariantDisks/IDDiskArbitrationUtils.hpp; sourceTree = "<group>"; };
70AE5AB122A3DBAA002C760A /* ZetaImportMenuDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ZetaImportMenuDelegate.mm; sourceTree = "<group>"; };
70AE5AB322A3DBBF002C760A /* ZetaImportMenuDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZetaImportMenuDelegate.h; sourceTree = "<group>"; };
70AE5AB422A3F7D3002C760A /* ZetaBaseDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZetaBaseDelegate.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -155,6 +160,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
70703F3722AD7633002C760A /* DiskArbitration.framework in Frameworks */,
7018764B20E7B55700BA39B8 /* libZFSWrapperStatic.a in Frameworks */,
7018765E20E7DA9900BA39B8 /* libzpool.1.dylib in Frameworks */,
7018764C20E7B57600BA39B8 /* libnvpair.1.dylib in Frameworks */,
Expand Down Expand Up @@ -238,6 +244,8 @@
709C1CAC1C354F8B00929DAE /* ZetaPoolWatcher.mm */,
70EABDBE1FF9992A00BA39B8 /* ZetaAuthorization.h */,
70EABDBF1FF9992A00BA39B8 /* ZetaAuthorization.m */,
70703F3822AD7A16002C760A /* IDDiskArbitrationUtils.cpp */,
70A60A4622AD7A5F002C760A /* IDDiskArbitrationUtils.hpp */,
7006C4841C26CA1500929DAE /* Assets.xcassets */,
70C930D622122CBD00BA39B8 /* Localizable.strings */,
7006C4861C26CA1500929DAE /* MainMenu.xib */,
Expand Down Expand Up @@ -287,6 +295,7 @@
70DB77B11FFAD8E300BA39B8 /* Frameworks */ = {
isa = PBXGroup;
children = (
70703F3622AD7633002C760A /* DiskArbitration.framework */,
);
name = Frameworks;
sourceTree = "<group>";
Expand Down Expand Up @@ -501,6 +510,7 @@
70EABDC41FF9A8D100BA39B8 /* CommonAuthorization.m in Sources */,
70EABDC01FF9992A00BA39B8 /* ZetaAuthorization.m in Sources */,
70AE5AB522A3F7D3002C760A /* ZetaBaseDelegate.m in Sources */,
70703F3922AD7A17002C760A /* IDDiskArbitrationUtils.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
263 changes: 263 additions & 0 deletions ZetaWatch/IDDiskArbitrationUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
//
// IDDiskArbitrationUtils.cpp
// InvariantDisks
//
// Created by Gerhard Röthlin on 2014.04.27.
// Copyright (c) 2014 the-color-black.net. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the conditions of the "3-Clause BSD" license described in the BSD.LICENSE file are met.
// Additional licensing options are described in the README file.
//

#include "IDDiskArbitrationUtils.hpp"

#include <IOKit/storage/IOStorageProtocolCharacteristics.h>

#include <sstream>

namespace ID
{
std::ostream & operator<<(std::ostream & os, DADiskRef disk)
{
return os << getDiskInformation(disk);
}

std::ostream & operator<<(std::ostream & os, DiskInformation const & disk)
{
return os << "Disk: (\n"
<< "\tVolumeKind=\"" << disk.volumeKind << "\"\n"
<< "\tVolumeUUID=\"" << disk.volumeUUID << "\"\n"
<< "\tVolumeName=\"" << disk.volumeName << "\"\n"
<< "\tVolumePath=\"" << disk.volumePath << "\"\n"
<< "\tMediaKind=\"" << disk.mediaKind << "\"\n"
<< "\tMediaType=\"" << disk.mediaType << "\"\n"
<< "\tMediaUUID=\"" << disk.mediaUUID << "\"\n"
<< "\tMediaBSDName=\"" << disk.mediaBSDName << "\"\n"
<< "\tMediaName=\"" << disk.mediaName << "\"\n"
<< "\tMediaPath=\"" << disk.mediaPath << "\"\n"
<< "\tMediaContent=\"" << disk.mediaContent << "\"\n"
<< "\tMedia(Whole,Leaf,Writable)=(" << disk.mediaWhole << ", "
<< disk.mediaLeaf << ", " << disk.mediaWritable << ")\n"
<< "\tDeviceGUID=\"" << disk.deviceGUID << "\"\n"
<< "\tDevicePath=\"" << disk.devicePath << "\"\n"
<< "\tDeviceProtocol=\"" << disk.deviceProtocol << "\"\n"
<< "\tDeviceModel=\"" << disk.deviceModel << "\"\n"
<< "\tBusName=\"" << disk.busName << "\"\n"
<< "\tBusPath=\"" << disk.busPath << "\"\n"
<< "\tIOSerial=\"" << disk.ioSerial << "\"\n"
<< "\tImagePath=\"" << disk.imagePath << "\"\n"
<< ")";
}

std::string to_string(CFStringRef str)
{
std::string result;
CFRange strRange = CFRangeMake(0, CFStringGetLength(str));
CFIndex strBytes = 0;
CFStringGetBytes(str, strRange, kCFStringEncodingUTF8, 0, false, nullptr, 0, &strBytes);
if (strBytes > 0)
{
result.resize(static_cast<size_t>(strBytes), '\0');
CFStringGetBytes(str, strRange, kCFStringEncodingUTF8, 0, false,
reinterpret_cast<UInt8*>(&result[0]), strBytes, nullptr);
}
return result;
}

std::string to_string(CFURLRef url)
{
CFStringRef str = CFURLCopyPath(url);
std::string result = to_string(str);
CFRelease(str);
return result;
}

std::string to_string(CFDataRef data)
{
char const * bytesBegin = reinterpret_cast<char const *>(CFDataGetBytePtr(data));
char const * bytesEnd = bytesBegin + CFDataGetLength(data);
std::stringstream ss;
ss << std::hex;
for (char const * byteIt = bytesBegin; byteIt != bytesEnd; ++byteIt)
ss << static_cast<unsigned>(*byteIt);
return ss.str();
}

std::string to_string(CFUUIDRef uuid)
{
CFStringRef str = CFUUIDCreateString(kCFAllocatorDefault, uuid);
std::string result = to_string(str);
CFRelease(str);
return result;
}

std::string to_string(CFTypeRef variant)
{
if (!variant)
return std::string();
CFTypeID typeID = CFGetTypeID(variant);
if (typeID == CFStringGetTypeID())
return to_string(CFStringRef(variant));
else if (typeID == CFURLGetTypeID())
return to_string(CFURLRef(variant));
else if (typeID == CFDataGetTypeID())
return to_string(CFDataRef(variant));
else if (typeID == CFUUIDGetTypeID())
return to_string(CFUUIDRef(variant));
return std::string();
}

std::string interpret_as_string(CFDataRef data)
{
char const * bytesBegin = reinterpret_cast<char const *>(CFDataGetBytePtr(data));
char const * bytesEnd = bytesBegin + CFDataGetLength(data);
return std::string(bytesBegin, bytesEnd);
}

template<typename T>
std::string stringFromDictionary(CFDictionaryRef dict, CFStringRef key)
{
if (T value = static_cast<T>(CFDictionaryGetValue(dict, key)))
return to_string(value);
return std::string();
}

int64_t numberFromDictionary(CFDictionaryRef dict, CFStringRef key)
{
if (CFNumberRef value = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, key)))
{
int64_t number = 0;
CFNumberGetValue(value, kCFNumberSInt64Type, &number);
return number;
}
return 0;
}

bool boolFromDictionary(CFDictionaryRef dict, CFStringRef key)
{
if (CFBooleanRef value = static_cast<CFBooleanRef>(CFDictionaryGetValue(dict, key)))
{
return CFBooleanGetValue(value);
}
return false;
}

std::string stringFromIOObjectWithParents(io_object_t ioObject, CFStringRef key)
{
std::string result;
CFTypeRef resultRef = IORegistryEntrySearchCFProperty(ioObject, kIOServicePlane, key,
kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
if (resultRef)
{
result = to_string(resultRef);
CFRelease(resultRef);
}
return result;
}

std::string serialNumberFromIOObject(io_object_t ioObject)
{
static CFStringRef const serialStrings[] = {
CFSTR("Serial Number"),
CFSTR("INQUIRY Unit Serial Number"),
CFSTR("USB Serial Number")
};
for (CFStringRef serialString: serialStrings)
{
std::string serial = stringFromIOObjectWithParents(ioObject, serialString);
if (!serial.empty())
return serial;
}
return std::string();
}

std::string imagePathFromIOObject(io_object_t ioObject)
{
std::string path;
CFStringRef key = CFSTR("image-path");
CFTypeRef resultRef = IORegistryEntrySearchCFProperty(ioObject, kIOServicePlane, key,
kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
if (resultRef)
{
if (CFGetTypeID(resultRef) == CFDataGetTypeID())
{
CFDataRef resultDataRef = CFDataRef(resultRef);
path = interpret_as_string(resultDataRef);
}
CFRelease(resultRef);
}
return path;
}

static std::string coreStorageMark = "/CoreStoragePhysical/";

DiskInformation getDiskInformation(DADiskRef disk)
{
DiskInformation info;
// DiskArbitration
CFDictionaryRef descDict = DADiskCopyDescription(disk);
info.volumeKind = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionVolumeKindKey);
info.volumeUUID = stringFromDictionary<CFUUIDRef>(descDict, kDADiskDescriptionVolumeUUIDKey);
info.volumeName = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionVolumeNameKey);
info.volumePath = stringFromDictionary<CFURLRef>(descDict, kDADiskDescriptionVolumePathKey);
info.mediaKind = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaKindKey);
info.mediaType = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaTypeKey);
info.mediaUUID = stringFromDictionary<CFUUIDRef>(descDict, kDADiskDescriptionMediaUUIDKey);
info.mediaBSDName = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaBSDNameKey);
info.mediaName = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaNameKey);
info.mediaPath = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaPathKey);
info.mediaContent = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaContentKey);
info.mediaWhole = boolFromDictionary(descDict, kDADiskDescriptionMediaWholeKey);
info.mediaLeaf = boolFromDictionary(descDict, kDADiskDescriptionMediaLeafKey);
info.mediaWritable = boolFromDictionary(descDict, kDADiskDescriptionMediaWritableKey);
info.deviceGUID = stringFromDictionary<CFDataRef>(descDict, kDADiskDescriptionDeviceGUIDKey);
info.devicePath = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionDevicePathKey);
info.deviceProtocol = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionDeviceProtocolKey);
info.deviceModel = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionDeviceModelKey);
info.busName = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionBusNameKey);
info.busPath = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionBusPathKey);
CFRelease(descDict);
// IOKit
io_service_t io = DADiskCopyIOMedia(disk);
info.ioSerial = serialNumberFromIOObject(io);
info.imagePath = imagePathFromIOObject(io);
CFMutableDictionaryRef ioDict = nullptr;
if (IORegistryEntryCreateCFProperties(io, &ioDict, kCFAllocatorDefault, 0) == kIOReturnSuccess)
{
// TODO: Pick out useful IOKit properties
CFRelease(ioDict);
}
IOObjectRelease(io);
// Guess wether this is an actual device
bool isCoreStorage = info.mediaPath.find(coreStorageMark) != std::string::npos;
bool isVirtual = info.deviceProtocol == kIOPropertyPhysicalInterconnectTypeVirtual;
info.isDevice = !isCoreStorage && !isVirtual;
return info;
}

bool isDevice(DiskInformation const & di)
{
return di.isDevice;
}

bool isWhole(DiskInformation const & di)
{
return di.mediaWhole;
}

std::string partitionSuffix(DiskInformation const & di)
{
if (!isWhole(di))
{
size_t suffixStart = di.mediaBSDName.find_last_not_of("0123456789");
if (suffixStart != std::string::npos &&
suffixStart+1 < di.mediaBSDName.size() &&
di.mediaBSDName[suffixStart] == 's')
{
return ':' + di.mediaBSDName.substr(suffixStart+1);
}
}
return std::string();
}
}
1 change: 1 addition & 0 deletions ZetaWatch/ZetaMenuDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ enum ZetaMenuTags

- (IBAction)importAllPools:(id)sender;
- (IBAction)mountAllFilesystems:(id)sender;
- (IBAction)copyRepresentedObject:(id)sender;

@end
Loading

0 comments on commit 34be689

Please sign in to comment.