I need to get the list of physical storage devices on an OS X system. IOServiceGetMatchingServices using the kIOStorageClass key gives me a list of all volumes, not all hardware storage devices. How do I do this?
The question is a little ambiguous (do you want whole drives, partitions, all of the above?), I suggest firing up the IORegistryExplorer utility (comes with XCode) and figuring out which class of device you want. I can tell you that each whole drive normally corresponds to an IOBlockStorageDriver, so maybe that's the class you want to match. It will then have an IOMedia client representing the whole device. It in turn will have a partition scheme client, which has an IOMedia client for each partition, unless it's not partitioned.
To get list of physical storage device you can match for kIOATABlockStorageDeviceClass. Following code obtains iterator for block storage devices.
IOReturn error = kIOReturnSuccess;
io_iterator_t iter = MACH_PORT_NULL;
error = IOServiceGetMatchingServices ( kIOMasterPortDefault,
IOServiceMatching ( kIOATABlockStorageDeviceClass ),
&iter );
Related
I'm trying to debug a libusb function called libusb_kernel_driver_active(). It tells if a USB device has an operating system driver attached to it. It takes an interface number as one of its arguments. I want to be able to find out which interface the operating system's driver is currently attached to. Is there a way to do this using a terminal command or IOKit?
I have tried IORegistryExplorer but it doesn't list this information.
ioreg does not appear to list USB interface information.
Maybe someone out there knows of an IOKit function that can tell us the information we want.
To find this information out, open the IORegistryExplorer program (spotlight can find it). Then select IOService from the drop down menu in the upper left corner of the window. In the search bar type the name of your device. If it is found select in on the tree below. Then delete all text from the search field to see all the available fields.
The IORegistryExplorer answer is correct, but as the question hints at, there are other ways to obtain the information, both on the Terminal and programmatically.
Terminal (ioreg)
The command
ioreg -irc IOUSBDevice
Will list all USB devices detected by the system, as well as any client objects in the I/O Registry. This means either the driver client directly (kext, dext, or user space) or the IOUSBInterface objects representing the different interfaces on a composite device, and the driver clients attached to each of those.
You can search by name instead of class type by using the -n option instead of -c but often the USB-level name doesn't match the retail name of the device, or is somehow abbreviated. It's usually easier to inspect all USB devices manually.
Programmatically
In your program, you can search for all USB devices in the system using something like this:
io_iterator_t device_iter = IO_OBJECT_NULL;
IOReturn ret = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(kIOUSBDeviceClassName), &device_iter);
if (ret == kIOReturnSuccess && device_iter != IO_OBJECT_NULL)
{
while (io_service_t device = IOIteratorNext(device_iter))
{
io_name_t device_name = "";
IORegistryEntryGetName(device, device_name);
// do something with device_nameā¦
}
}
Once you have selected your device, you can then use IORegistryEntryCreateIterator() to iterate over its child objects (possibly recursively), which should allow you to identify the driver being used or obtain any other information you require.
When creating a new CIContext with Metal device one has to provide which device (a GPU) to use:
let context = CIContext(
mtlDevice: device
)
On my MacBook Pro for the development purposes I always pick the device associated with the screen with MTLCreateSystemDefaultDevice() method:
guard
let device:MTLDevice = MTLCreateSystemDefaultDevice()
else {
exit(EXIT_FAILURE)
}
However on a Mac Pro which will be used in production in a headless mode there are two GPU cards that I can target. In order to get all available devices one can use MTLCopyAllDevices() method which gives the following output on my Mac Pro:
[
<MTLDebugDevice: 0x103305450> -> <BronzeMtlDevice: 0x10480a200>
name = AMD Radeon HD - FirePro D700
<MTLDebugDevice: 0x103307730> -> <BronzeMtlDevice: 0x104814800>
name = AMD Radeon HD - FirePro D700
]
This Mac Pro will be utilised heavily with hundreds of small tasks per second and every time the new task comes in I need to select a GPU device on which the task will be processed.
Now the question is - is picking a random device from the above array a good idea:
let devices = MTLCopyAllDevices() // get all available devices
let rand = Int(arc4random_uniform(UInt32(devices.count))) // random index
let device = devices[rand] // randomly selected GPU to use
let context = CIContext(
mtlDevice: device
)
Since there are two equal GPU devices on a Mac Pro, targeting always one will be a waste of resources. Logic tells me that with the above code both GPUs will be utilised equally but maybe I'm wrong and MacOS offer some kind of abstraction layer that will intelligently pick the GPU which is less utilised at the time of execution?
Thank you in advance.
Why not just alternate between them? Even if you're committing command buffers from multiple threads, the work should be spread roughly evenly:
device = devices[taskIndex % devices.count]
Also, make sure to avoid creating CIContexts for every operation; those are expensive, so you should keep a list of contexts (one per device) instead.
Note that if you're doing any of your own Metal work (as opposed to just Core Image filtering), you'll need to have a command queue for each device, and any resources you want to use will need to be allocated by their respective device (resources can't be shared by MTLDevices).
I'm working on a cocoa app that detects any USB storage device (flash disk, Smartphone...) connected to the Mac and then use its files.When creating the matching dictionary I have to specify some keys and their values to only detect storage devices. I'm working on Mac os x.
Question : What keys should I specify in the matching dictionary to only detect every storage USB device? and what should be their values?
Is this I/O Kit matching or disk arbitration matching?
For the former, I don't think there's a clean way to match the IOMedia object, because that would require matching against more than one level of the I/O Kit device tree (with at least one level in between). So you have to do a passive match against the IOMedia object and then examine its provider's provider('s provider's provider...) to determine whether to actually match, e.g. match against:
<key>IOProviderClass</key>
<string>IOMedia</string>
<key>IOPropertyMatch</key>
<dict>
<key>Whole</key>
<true/>
</dict>
And then iterate your way up the tree until you find a node that contains a "Protocol Characteristics" dictionary and examine its "Physical Interconnect" property to see if it says "USB".
I'm not 100% certain that there's not a simpler way, but I don't know about it if it exists.
If you're using the Disk Arbitration framework, it is easy:
CFMutableDictionaryRef matchingDict =
CFDictionaryCreateMutable(
kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(matchingDict,
kDADiskDescriptionDeviceProtocolKey,
CFSTR(kIOPropertyPhysicalInterconnectTypeUSB));
(quoted from the Disk Arbitration Programming Guide). From there, you can get the underlying IOMedia object by calling the DADiskCopyIOMedia function, which makes that probably the better API, assuming you're not doing in-kernel matching.
For other folks who might read this answer in the future, if you happen to be doing in-kernel matching for a kext that needs to attach to an IOMedia nub, just walk the provider chain in your probe method, and return either an instance of your class (to allow your driver to attach) or NULL (to reject that IOMedia object). Obviously that doesn't apply to a Cocoa app. Count your blessings. :-)
How to uniquely identify computer (mainboard) using C#(.Net/Mono, local application)?
Edition. We can identify mainboard in .Net using something like this (see Get Unique System Identifiers in C#):
using System.Management;
...
ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_MotherboardDevice");
...
But unfortunately Mono does not support System.Management. How to do it under Mono for Linux? - I don't know :(
Write a function that takes a few unique hardware parameters as input and generates a hash out of them.
For example, Windows activation looks at the following hardware characteristics:
Display Adapter
SCSI Adapter
IDE Adapter (effectively the motherboard)
Network Adapter (NIC) and its MAC Address
RAM Amount Range (i.e., 0-64mb, 64-128mb, etc.)
Processor Type
Processor Serial Number
Hard Drive Device
Hard Drive Volume Serial Number (VSN)
CD-ROM / CD-RW / DVD-ROM
You can pick up a few of them to generate your unique computer identifier.
Please see: Get Unique System Identifiers in C#
You realistically have MotherboardID, CPUID, Disk Serial and MAC address, from experience none of them are 100%.
Our stats show
Disk serial Is missing 0.1 %
MAC Is missing 1.3 %
Motherboard ID Is missing 30 %
CPUID Is missing 99 %
0.04% of machines tested yielded no information, we couldn't even read the computer name. It maybe that these were some kind of virtual PC, HyperV or VMWare instance, or maybe just very locked down? In any case your design has to be able to cope with these cases.
Disk serial is the most reliable, but easy to change, mac can be changed and depending on the filtering applied when reading it can change if device drivers are added (hyperv, wireshark etc).
Motherboard and CPUID sometimes return values that are invalid "NONE", "AAAA..", "XXXX..." etc.
You should also note that these functions can be very slow to call (they may take a few seconds even on a fast PC), so it may be worth kicking them off on a background thread as early as possible, you ideally don't want to be blocking on them.
Try this:
http://carso-owen.blogspot.com/2007/02/how-to-get-my-motherboard-serial-number.html
Personally though, I'd go with hard drive serial number. If a mainboard dies and is replaced, that PC isn't valid any more. If the HDD drive is replaced, it doesn't matter too much because the software was on it.
Of course, on the other hand, if the HDD is just moved elsewhere, the information goes with it, so you might want to look at a combination of serial numbers, depending what you want it for.
How about the MAC address of the network card?
I want to update a list of storage devices as the user inserts USB keys, adds external disks and mounts disk images. IOKit's IOServiceAddInterestNotification looks like the way to go, but the obvious use of registering general interest in kIOMediaClass only gives you notifications for unmounting of volumes and then only sometimes.
What's the right way to do this?
The following calls in DiskArbitration.h do exactly what I want:
DARegisterDiskAppearedCallback
DARegisterDiskDisappearedCallback
DARegisterDiskDescriptionChangedCallback
These cover insertion, removal (even of unmountable volumes)
metadata change events.
P.S. Don't forget to add your DASession to a runloop
or you won't get any callbacks.
I want to update a list of storage devices as the user inserts USB keys, adds external disks and mounts disk images.
I can get you two out of three with this piece of code, which I imagine wouldn't require a lot more work to give you the third.
File: USBNotificationExample.c
Description: This sample demonstrates how to use IOKitLib and IOUSBLib to set up asynchronous
callbacks when a USB device is attached to or removed from the system.
It also shows how to associate arbitrary data with each device instance.
http://opensource.apple.com/source/IOUSBFamily/IOUSBFamily-385.4.1/Examples/Another%20USB%20Notification%20Example/USBNotificationExample.c
I've personally used (a slightly modified copy of this code) for a long time, to monitor the connection of USB HDDs.
As you can see from this small sample, it may easily prove adaptable to monitor mounted drives. Or it may not. YMMV.
matchingDict = IOServiceMatching(kIOUSBDeviceClassName); // Interested in instances of class
// IOUSBDevice and its subclasses
and when it matches
void DeviceAdded(void *refCon, io_iterator_t iterator)
{
kern_return_t kr;
io_service_t usbDevice;
IOCFPlugInInterface **plugInInterface=NULL;
SInt32 score;
HRESULT res;
while ( (usbDevice = IOIteratorNext(iterator)) )
{
io_name_t deviceName;
CFStringRef deviceNameAsCFString;
MyPrivateData *privateDataRef = NULL;
UInt32 locationID;
printf("Device 0x%08x added.\n", usbDevice);
and so forth, and so on.
Would watching /Volumes for changes do what you need?
If you happen to be working at the Cocoa level, you can also register to receive the following notifications from NSWorkspace:
NSWorkspaceDidMountNotification
NSWorkspaceDidRenameVolumeNotification
NSWorkspaceWillUnmountNotification
NSWorkspaceDidUnmountNotification