Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Retrieving USB Serial Number on OsX

5.00/5 (2 votes)
21 Oct 2015CPOL 12.2K  
A short code snippet to fetch the USB Serial Number of a file name residing on a stick.

Introduction

The USB Serial Number is one unique number you might wish to use to identify a device- for licensing or whatever. However, keep in mind it is in no way guarded against forging and you can buy special hardware where this ID can be set by the user.

There are other snippets on the web on how to do this (e.g., http://oroboro.com/usb-serial-number-osx/), but they require much more code.

How the Code Works

First, a DADiskRef is created for the file by recursively stripping path components until the mount point is found. It then obtains the io_service object and searches it using IORegistryEntrySearchCFProperty for the key "USB Serial Number".

Using the Code

See below. Requires IOKit and DiskArbitration Frameworks. Uses functions existing since OSX 10.7.

C++
#include <iostream>
#include <string>
#include <CoreFoundation/CoreFoundation.h>
#include <DiskArbitration/DADisk.h>

#include <IOKit/IOKitLib.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>
#include <sys/stat.h>

using namespace::std;

// path_in is a filename on an usb disk
// This will fetch the serial for this usb disk
// provided apple does not change the usb serial key name from
// "USB Serial Number" to whatever.
//
// Usage : string sSerial = GetSerial("/Volumes/USBStick/MyDir/Myfile");
// Returns "" if file is not on a USB Disk
//

string GetSerial(const string &path_in)
    {
    DASessionRef session = DASessionCreate(NULL);
    DADiskRef disk;

    // We need to find the mount point- strip last component:
    string path(path_in);
    size_t nPath = path_in.find_last_of("/");
    if(nPath != string::npos)
        {
        path=path_in.substr(0, nPath);
        }
    else
        return "";

    if (session)
        {
        CFURLRef url = CFURLCreateFromFileSystemRepresentation
        (NULL, (const UInt8 *)path.c_str(), path.length(), TRUE);
        disk = DADiskCreateFromVolumePath(NULL, session, url);
        CFRelease(url);
        if(disk)
            {
            // We found a mount point...
            io_service_t ioService = DADiskCopyIOMedia( disk );
            CFStringRef key = CFSTR("USB Serial Number");
            CFTypeRef sResult ;

            sResult = IORegistryEntrySearchCFProperty( ioService, kIOServicePlane,
                                                      key, NULL,
                                                      kIORegistryIterateParents | 
                                                      kIORegistryIterateRecursively ) ;
            if(sResult)
                {
                string sValue( CFStringRefToStdString((CFStringRef)sResult) ) ;

                cerr << "GetSerialBetter got " << sValue << endl;
                return sValue;
                }
            }
        else
            {
            // recurse down path until we find a mount point ...
            path = path.substr(0, path.length()-1); // remove trailing "/"
            return GetSerial(path);
            }
        }

    return "";
    }

This uses this tiny function to map CFStringRefs to std::string.

C++
string  CFStringRefToStdString(const CFStringRef pCFStringRef)
{
    const char* pCStr = NULL;
    
    string sRet;
    
    if (pCFStringRef)
        {
        pCStr = CFStringGetCStringPtr(pCFStringRef, kCFStringEncodingMacRoman);
        if(pCStr)
            sRet.assign(pCStr);
        }
    return sRet;
}

History

  • V1.0: Works for me

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)