Gerald
Gerald

Reputation: 23499

Unique hardware ID in Mac OS X

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++.

Upvotes: 32

Views: 33793

Answers (9)

fny
fny

Reputation: 33605

The following is equivalent and far simpler than the ioreg command.

system_profiler SPHardwareDataType | awk '/UUID/ { print $3 }'

Upvotes: 1

yairchu
yairchu

Reputation: 24814

For C/C++:

#include <IOKit/IOKitLib.h>

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);    
}

Upvotes: 42

Azeem.Butt
Azeem.Butt

Reputation: 5861

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];
}

Upvotes: 9

zhanglin
zhanglin

Reputation: 166

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.

Upvotes: 12

Nitinkumar Ambekar
Nitinkumar Ambekar

Reputation: 1009

/*
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;
}

Upvotes: 7

xyz
xyz

Reputation: 27857

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];

Upvotes: 19

Brock Woolf
Brock Woolf

Reputation: 47302

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];

Upvotes: 1

Singletoned
Singletoned

Reputation: 5129

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).

Upvotes: 0

kbyrd
kbyrd

Reputation: 3351

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.

Upvotes: 1

Related Questions