views:

1318

answers:

6

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

+1  A: 

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.

kbyrd
There are actually some Macs that have shipped without a serial number, so you shouldn't do anything that relies 100% on having a unique serial number available.
smorgan
`system_profiler` will also sometimes take a while. If you've got a disc in the DVD drive it'll spin up, for example.
Dietrich Epp
A: 

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

Singletoned
+5  A: 

Try this Terminal command:

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

From here

frou
Thanks, this seems to be the way that works the best. The System Profiler output seems to vary on different systems so makes me fear a flood of support calls not being able to register the software.
Gerald
+2  A: 

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];
Brock Woolf
What's with the cast to `NSString*`, and why call `lastPathComponent`? That line is equivalent to `[args addObject:@"Finder"]`.
dreamlax
+2  A: 

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: LocalString(@"kEthernetBSDName")] )
     {
      macAddress = [(NSString*)SCNetworkInterfaceGetHardwareAddressString(curInterface) mutableCopy];

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

      break;
     }
    }

    return [[macAddress copy] autorelease];
}
Azeem.Butt
You're right I should have specified the language. I updated the question and tags. I am using C++ and the Qt framework for cross-platform development.
Gerald
Then SCNetworkInterfaceGetHardwareAddressString will get it for you without forking another process to run a shell script.
Azeem.Butt
+2  A: 

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