Question

Mac OS X development is a fairly new animal for me, and I'm in the process of porting over some software. For software licensing and registration I need to be able to generate some kind of hardware ID. It doesn't have to be anything fancy; Ethernet MAC address, hard drive serial, CPU serial, something like that.

I've got it covered on Windows, but I haven't a clue on Mac. Any idea of what I need to do, or where I can go for information on this would be great!

Edit:

For anybody else that is interested in this, this is the code I ended up using with Qt's QProcess class:

QProcess proc;

QStringList args;
args << "-c" << "ioreg -rd1 -c IOPlatformExpertDevice |  awk '/IOPlatformUUID/ { print $3; }'";
proc.start( "/bin/bash", args );
proc.waitForFinished();

QString uID = proc.readAll();

Note: I'm using C++.

Was it helpful?

Solution

Try this Terminal command:

ioreg -rd1 -c IOPlatformExpertDevice | awk '/IOPlatformUUID/ { split($0, line, "\""); printf("%s\n", line[4]); }'

From here

Here is that command wrapped in Cocoa (which could probably be made a bit cleaner):

NSArray * args = [NSArray arrayWithObjects:@"-rd1", @"-c", @"IOPlatformExpertDevice", @"|", @"grep", @"model", nil];
NSTask * task = [NSTask new];
[task setLaunchPath:@"/usr/sbin/ioreg"];
[task setArguments:args];

NSPipe * pipe = [NSPipe new];
[task setStandardOutput:pipe];
[task launch];

NSArray * args2 = [NSArray arrayWithObjects:@"/IOPlatformUUID/ { split($0, line, \"\\\"\"); printf(\"%s\\n\", line[4]); }", nil];
NSTask * task2 = [NSTask new];
[task2 setLaunchPath:@"/usr/bin/awk"];
[task2 setArguments:args2];

NSPipe * pipe2 = [NSPipe new];
[task2 setStandardInput:pipe];
[task2 setStandardOutput:pipe2];
NSFileHandle * fileHandle2 = [pipe2 fileHandleForReading];
[task2 launch];

NSData * data = [fileHandle2 readDataToEndOfFile];
NSString * uuid = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

OTHER TIPS

For C/C++:

void get_platform_uuid(char * buf, int bufSize) {
    io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/");
    CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
    IOObjectRelease(ioRegistryRoot);
    CFStringGetCString(uuidCf, buf, bufSize, kCFStringEncodingMacRoman);
    CFRelease(uuidCf);    
}

Why not try gethostuuid()? Here's the documentation from the Mac OS X System Calls Manual:

NAME:

 gethostuuid -- return a unique identifier for the current machine

SYNOPSIS:

 #include <unistd.h>

 int gethostuuid(uuid_t id, const struct timespec *wait);

DESCRIPTION:

The gethostuuid() function returns a 16-byte uuid_t specified by id, that uniquely identifies the current machine. Be aware that the hardware identifiers that gethostuuid() uses to generate the UUID can themselves be modified.

The wait argument is a pointer to a struct timespec that specifies the maximum time to wait for the result. Setting the tv_sec and tv_nsec fields to zero means to wait indefinitely until it completes.

RETURN VALUES:

The gethostuuid() function returns zero on success or -1 on error.

ERRORS

The gethostuuid() functions fails if:

 [EFAULT]           wait points to memory that is not a valid part of the
                    process address space.

 [EWOULDBLOCK]      The wait timeout expired before the UUID could be
                    obtained.

This would be easier to answer if you told us what language you were using. The information is obtainable without any shell commands through the SystemConfiguration framework, and also through IOKit if you want to get your hands really dirty.

- (NSString*) getMACAddress: (BOOL)stripColons {
    NSMutableString         *macAddress         = nil;
    NSArray                 *allInterfaces      = (NSArray*)SCNetworkInterfaceCopyAll();
    NSEnumerator            *interfaceWalker    = [allInterfaces objectEnumerator];
    SCNetworkInterfaceRef   curInterface        = nil;

    while ( curInterface = (SCNetworkInterfaceRef)[interfaceWalker nextObject] ) {
        if ( [(NSString*)SCNetworkInterfaceGetBSDName(curInterface) isEqualToString:@"en0"] ) {
            macAddress = [[(NSString*)SCNetworkInterfaceGetHardwareAddressString(curInterface) mutableCopy] autorelease];

            if ( stripColons == YES ) {
                [macAddress replaceOccurrencesOfString: @":" withString: @"" options: NSLiteralSearch range: NSMakeRange(0, [macAddress length])];
            }

            break;
        }
    }

    return [[macAddress copy] autorelease];
}
/*
g++ mac_uuid.cpp -framework CoreFoundation -lIOKit
*/


#include <iostream>
#include <IOKit/IOKitLib.h>

using namespace std;

void get_platform_uuid(char * buf, int bufSize)
{
   io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/");
   CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
   IOObjectRelease(ioRegistryRoot);
   CFStringGetCString(uuidCf, buf, bufSize, kCFStringEncodingMacRoman);
   CFRelease(uuidCf);
}

int main()
{
   char buf[512] = "";
   get_platform_uuid(buf, sizeof(buf));
   cout << buf << endl;
}

Running:

system_profiler | grep 'Serial Number (system)'

in a terminal returns what it likely a unique id. That works on my 10.5 box, I'm not sure what the correct string will be in other versions of OS X.

As some people above have hinted, you can use a Terminal command to get a hardware ID.

I assume you want to do this in code however so I would take a look at the NSTask class in Cocoa. It basically lets you run terminal commands inside your application.

This code is an example of how to use NSTask in Cocoa. It sets up the environment to execute the "killall" command. It passes it the arguement "Finder".

It's the equivilent of running "killall Finder" on the command line, which will kill the Finder obviously.

NSTask *aTask = [[NSTask alloc] init];
NSMutableArray *args = [NSMutableArray array];

[aTask setLaunchPath: @"/usr/bin/killall"];
[args addObject:[@"/Applications/Finder" lastPathComponent]];
[aTask setArguments:args];
[aTask launch];

[aTask release];

System Profiler (in Applications - Utilities) contains most of this kind of info. It has your serial number and your mac address (no relation to Mac. All computers have a mac address which is pretty much unique to every network card).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top