I'd like to find the identifiers of attached drives - as seen in the Terminal command diskutil list
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *1.0 TB disk0
1: EFI EFI 209.7 MB disk0s1
2: Apple_HFS SSHD OSX 511.7 GB disk0s2
3: Apple_Boot Recovery HD 650.0 MB disk0s3
4: Apple_HFS SSHD OSX NEW 511.0 GB disk0s4
5: Apple_Boot Recovery HD 650.0 MB disk0s5
So far I've managed to write this code:
var volume_stack = [NSURL]()
volume_stack = NSFileManager.defaultManager().mountedVolumeURLsIncludingResourceValuesForKeys([NSURLVolumeNameKey, NSURLVolumeIdentifierKey], options: [])!
for disk: NSURL in volume_stack {
do {
var info: Dictionary = [String : AnyObject]()
info = try disk.resourceValuesForKeys([NSURLVolumeIdentifierKey])
for (key, value) in info {
var s_value = String(data: value as! NSData, encoding: NSUTF8StringEncoding)
print("key: \(key) value: \(s_value)")
}
}
catch {
print ("ERROR")
}
}
but the output is:
key: NSURLVolumeIdentifierKey value: Optional("gEd\0\0\0\0\0")
key: NSURLVolumeIdentifierKey value: nil
key: NSURLVolumeIdentifierKey value: nil
key: NSURLVolumeIdentifierKey value: Optional("sHg\0\0\0\0\0")
a log of the ivar value
instead of s_value
gives
key: NSURLVolumeIdentifierKey value: <67456400 00000000>
key: NSURLVolumeIdentifierKey value: <c6236500 00000000>
key: NSURLVolumeIdentifierKey value: <69986600 00000000>
key: NSURLVolumeIdentifierKey value: <73486700 00000000>
and from what I can tell it's NSData
. Apologies for the badly written code but it's my first Swift app and I've been going around in circles so it's become a little unsophisticated. Is there a way to obtain what's being listed in the identifier column as a String
?
Use DiskArbitration.framework
At a high level, you can use the Disk Arbitration framework to:
- Receive notification of disk-related events (disk ejection, for example) and participate in the arbitration process (preventing disk ejection, for example).
- Obtain information about disks and manipulate disks (requesting that a disk be ejected, for example).
First create a global session with DASessionCreate
, then create a disk reference with DADiskCreateFromVolumePath
for each mounted volume and get the BSD name (identifier) with DADiskGetBSDName
. Convert the C-string to String
and you are done.
if let session = DASessionCreate(kCFAllocatorDefault) {
let mountedVolumeURLs = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: nil)!
for volumeURL in mountedVolumeURLs {
if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volumeURL as CFURL),
let bsdName = DADiskGetBSDName(disk) {
let bsdString = String(cString : bsdName)
print(volumeURL.path, bsdString)
}
}
}
Another suitable way is to parse IORegistry.
Another (possibly easier) way would be to call the BSD function statfs()
. In plain C, you'd use:
struct statfs fsinfo;
statfs("/", &fsinfo);
printf("root device path: %s\n", fsinfo.f_mntfromname);
That'll print something like "/dev/disk1s3"
Here's an example calling statfs
from Swift
import Darwin
extension String {
/// See https://oleb.net/blog/2017/12/swift-imports-fixed-size-c-arrays-as-tuples/
init<T>(tupleOfCChars: T, length: Int = Int.max) {
self = withUnsafePointer(to: tupleOfCChars) { pointer -> String in
let count = MemoryLayout<T>.size / MemoryLayout<CChar>.size
return pointer.withMemoryRebound(to: CChar.self, capacity: count) { cCharPointer in
return String(cString: cCharPointer)
}
}
}
}
var fsInfo = statfs()
statfs("/", &fsInfo)
let fileSystemMountName = String(tupleOfCChars: fsInfo.f_mntfromname)
print(fileSystemMountName) // => /dev/disk1s5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With