Edit AllPages

<– is that OK??

Nobody helped me (see the Original Post below). Snif. But I figured it out by myself. What finally got me started was the addition of ‘Carbon’ in my googles searches (I had tried several times before with no luck).

Of course, I still put the code here with links to where I found the code (see The Solution below). Please feel free to add more in the code section…


Original post - nobody helped me )`:

I am trying to get some basic profile of the machine running my Cocoa program, in particular:

So I want something like a light system profile. I have found some info out there and have some working code for the number of processors, and the type of processor (see GettingTheProcessor). I can get the hostnames through NSHost. The rest, I don’t know! I looked hard, and could not find anything obvious. Even the RendezVous thing is quite obscure It seems IOKit / IORegistry could help for some of that. Useful links eith some tutorials/example would also help. Maybe somebody has written some Cocoa wrapper for all that stuff.

Thanks for any help you can provide. I will put all the code I can get to work back here, of course.


The Solution

Dont’ forget in Xcode: it seems you have to link against the Carbon, SystemConfiguration and IOKit frameworks.


@interface CPSystemInformation : NSObject {}

//all the info at once!


#import “CPSystemInformation.h”

#import <Carbon/Carbon.h> #import <SystemConfiguration/SystemConfiguration.h>

@implementation CPSystemInformation

//get everything!

#pragma mark ** Getting the Human Name for the Machine Type **

/* adapted from / /see below ‘humanMachineNameFromNilZeroCom()’ for the original code / /this code used a dictionary insted - see ‘translationDictionary()’ below */

//non-human readable machine type/model

//dictionary used to make the machine type human-readable static NSDictionary *translationDictionary=nil;

@”iMac (first generation)”,@”iMac,1”, @”iMac (first generation) - unknown model”,@”iMac”, @”PowerBook G3 (Lombard)”,@”PowerBook1,1”, @”iBook (clamshell)”,@”PowerBook2,1”, @”iBook FireWire (clamshell)”,@”PowerBook2,2”, @”PowerBook G3 (Pismo)”,@”PowerBook3,1”, @”PowerBook G4 (Titanium)”,@”PowerBook3,2”, @”PowerBook G4 (Titanium w/ Gigabit Ethernet)”, @”PowerBook3,3”, @”PowerBook G4 (Titanium w/ DVI)”,@”PowerBook3,4”, @”PowerBook G4 (Titanium 1GHZ)”,@”PowerBook3,5”, @”iBook (12in May 2001)”,@”PowerBook4,1”, @”iBook (May 2002)”,@”PowerBook4,2”, @”iBook 2 rev. 2 (w/ or w/o 14in LCD) (Nov 2002)”, @”PowerBook4,3”, @”iBook 2 (w/ or w/o 14in LDC)”,@”PowerBook4,4”, @”PowerBook G4 (Aluminum 17in)”,@”PowerBook5,1”, @”PowerBook G4 (Aluminum 15in)”,@”PowerBook5,2”, @”PowerBook G4 (Aluminum 17in rev. 2)”,@”PowerBook5,3”, @”PowerBook G4 (Aluminum 12in)”,@”PowerBook6,1”, @”PowerBook G4 (Aluminum 12in)”,@”PowerBook6,2”, @”iBook G4”,@”PowerBook6,3”, @”PowerBook or iBook - unknown model”,@”PowerBook”, @”Blue & White G3”,@”PowerMac1,1”, @”PowerMac G4 PCI Graphics”,@”PowerMac1,2”, @”iMac FireWire (CRT)”,@”PowerMac2,1”, @”iMac FireWire (CRT)”,@”PowerMac2,2”, @”PowerMac G4 AGP Graphics”,@”PowerMac3,1”, @”PowerMac G4 AGP Graphics”,@”PowerMac3,2”, @”PowerMac G4 AGP Graphics”,@”PowerMac3,3”, @”PowerMac G4 (QuickSilver)”,@”PowerMac3,4”, @”PowerMac G4 (QuickSilver)”,@”PowerMac3,5”, @”PowerMac G4 (MDD/Windtunnel)”,@”PowerMac3,6”, @”iMac (Flower Power)”,@”PowerMac4,1”, @”iMac (Flat Panel 15in)”,@”PowerMac4,2”, @”eMac”,@”PowerMac4,4”, @”iMac (Flat Panel 17in)”,@”PowerMac4,5”, @”PowerMac G4 Cube”,@”PowerMac5,1”, @”PowerMac G4 Cube”,@”PowerMac5,2”, @”iMac (Flat Panel 17in)”,@”PowerMac6,1”, @”PowerMac G5”,@”PowerMac7,2”, @”PowerMac G5”,@”PowerMac7,3”, @”PowerMac - unknown model”,@”PowerMac”, @”XServe”,@”RackMac1,1”, @”XServe rev. 2”,@”RackMac1,2”, @”XServe G5”,@”RackMac3,1”, @”XServe - unknown model”,@”RackMac”, @”Mac Mini”,@”Macmini1,1”, // Seen on a 1st gen. Core Duo, but may also be on others…? @”Mac Mini - unknown model”,@”Macmini”, nil]; return translationDictionary;


machineType=[self machineType]; //return the corresponding entry in the NSDictionary NSDictionary *translation=[self translationDictionary]; NSString *aKey; //keys should be sorted to distinguish ‘generic’ from ‘specific’ names NSEnumerator *e=[translation allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; [[NSRange r; while (aKey=[e nextObject]) { r=[machineType rangeOfString:aKey]; if (r.location!=NSNotFound) //continue searching : the first hit will be the generic name human=[translation objectForKey:aKey]; } if (human) return human; else return machineType;


//for some reason, this does not work //probably old stuff still around

#pragma mark ** Getting Processor info **

#include <mach/mach_host.h> #include <mach/host_info.h>

infoCount = HOST_BASIC_INFO_COUNT; host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount); return (unsigned int)(hostInfo.max_cpus);


#include <mach/mach.h> #include <mach/machine.h>

// the following methods were more or less copied from // // // and can be better understood with a look at // file:///usr/include/mach/machine.h

infoCount = HOST_BASIC_INFO_COUNT; kern_return_t ret = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount); return ( (KERN_SUCCESS == ret) && (hostInfo.cpu_type == CPU_TYPE_POWERPC) );


infoCount = HOST_BASIC_INFO_COUNT; kern_return_t ret = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount); return ( (KERN_SUCCESS == ret) && (hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_750) );


infoCount = HOST_BASIC_INFO_COUNT; kern_return_t ret = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount); return ( (KERN_SUCCESS == ret) && (hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_7400 || hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_7450));


#ifndef CPU_SUBTYPE_POWERPC_970 #define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100) #endif

infoCount = HOST_BASIC_INFO_COUNT; kern_return_t ret = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount); return ( (KERN_SUCCESS == ret) && (hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970));



#pragma mark ** Machine information **

//this used to be called ‘Rendezvous name’ (X.2), now just ‘Computer name’ (X.3) //see here for why: //this is the name set in the Sharing pref pane

/* copied from / / and modified by / / and by */

kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
if (kr == noErr) { entry = IORegistryGetRootEntry(masterPort); if (entry != MACH_PORT_NULL) { prop = IORegistryEntrySearchCFProperty(entry, kIODeviceTreePlane, CFSTR(“serial-number”),
                                     nil, kIORegistryIterateRecursively);
 			if (prop == nil) {
 				result = @"null";
 			} else {
 				propID = CFGetTypeID(prop);
 			if (propID == CFDataGetTypeID()) {
 				propData = (CFDataRef)prop;
 				bufSize = CFDataGetLength(propData);
 				if (bufSize > 0) {
 					data = CFDataGetBytePtr(propData);
 					if (data) {
 						i = 0;
 						s = data;
 						t = firstPart;
 						while (i < bufSize) {
 							if (*s != '\0') {
 								*t++ = *s++;
 							} else {
 						*t = '\0';
while ((i < bufSize) && (*s == ‘\0’)) { i++; s++; } t = secondPart; while (i < bufSize) { i++; if (*s != ‘\0’) { *t++ = *s++; } else { break; } } *t = ‘\0’; result = [NSString stringWithFormat: @”%s%s”,secondPart,firstPart]; } } } } mach_port_deallocate(mach_task_self(), masterPort); } return(result);


#pragma mark ** System version **


Some more code from when this topic came up on Cocoa-Dev:

The first gets you the physical RAM size in MBs. You could also get it in bytes, but since Gestalt returns a signed 32-bit number, this would not be able to return any RAM above 2GB, which is an amount that increasingly more and more Macs these days seem to have.

unsigned UKPhysicalRAMSize() // In MBs. { long ramSize;

if( Gestalt( gestaltPhysicalRAMSizeInMegabytes, &ramSize ) == noErr )
	return ramSize;
	return 0; }

And here’s another approach to get the system version:

NSString* UKSystemVersion() { long sysVersion;

if( Gestalt( gestaltSystemVersion, &sysVersion ) != noErr )
	return nil;

int		majorHiNib, majorLoNib, minorNib, bugNib;

majorHiNib = (sysVersion & 0x0000F000) >> 12;
majorLoNib = (sysVersion & 0x00000F00) >> 8;
minorNib = (sysVersion & 0x000000F0) >> 4;
bugNib = sysVersion & 0x0000000F;

if( majorHiNib == 0 )
	return [NSString stringWithFormat: @"%ld.%ld.%ld", majorLoNib, minorNib, bugNib];
	return [NSString stringWithFormat: @"%ld%ld.%ld.%ld", majorHiNib, majorLoNib, minorNib, bugNib]; }

This is also a nice example on how to decode BCD numbers as Carbon uses them to store version numbers. It’s unlikely you’ll ever hit the case where you have a one-digit number in front of the system version, but maybe if your app parses ‘vers’ resources or gets some other version number in BCD you’ll want to borrow this code.

Oh, and finally, here’s a variation of the serial number getting code. I think my version is a little more readable:

NSString* UKSystemSerialNumber() { mach_port_t masterPort; kern_return_t kr = noErr; io_registry_entry_t entry; CFTypeRef prop; CFTypeID propID; NSString* str = nil;

kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
if( kr != noErr )
	goto cleanup;
entry = IORegistryGetRootEntry( masterPort );
if( entry == MACH_PORT_NULL )
	goto cleanup;
prop = IORegistryEntrySearchCFProperty(entry, kIODeviceTreePlane, CFSTR("serial-number"), nil, kIORegistryIterateRecursively);
if( prop == nil )
	goto cleanup;
propID = CFGetTypeID( prop );
if( propID != CFDataGetTypeID() )
	goto cleanup;

const char*	buf = [(NSData*)prop bytes];
int			len = [(NSData*)prop length],

char	secondPart[256];
char	firstPart[256];
char*	currStr = secondPart; // Version number starts with second part, then NULLs, then first part.
int		y = 0;

for( x = 0; x < len; x++ )
	if( buf[x] > 0 && (y < 255) )
		currStr[y++] = buf[x];
	else if( currStr == secondPart )
		currStr[y] = 0;		// Terminate string.
		currStr = firstPart;
		y = 0;
currStr[y] = 0;	// Terminate string.

str = [NSString stringWithFormat: @"%s%s", firstPart, secondPart];

cleanup: mach_port_deallocate( mach_task_self(), masterPort );

return str; }

The above serial number code produced incorrect results on my new MacBook, so I did some searching. Starting with Panther, the serial number is available in the IOPlatformSerialNumber property of the the IOPlatformExpertDevice node in the I/O registry. See: -DanTreiman

Do you know <sys/sysctl.h> ? It has some features to get various informations about the installed hardware and is (afaik) portable (runs not only on Darwin). For an example see the manpage by Apple: Another example shows, how to get the physical RAM of your machine:

#import <sys/sysctl.h>

#define GB (102410241024) // 1 Gigabyte of RAM

int error = 0 ; int value = 0 ; unsigned long length = sizeof(value) ;

int selection[2] = { CTL_HW, HW_PHYSMEM } ;

error = sysctl(selection, 2, &value, &length, NULL, 0) ;

if ( error == 0 ) { NSLog(@”Your machine has %i Bytes of RAM (%f GB)”, value, (value / GB)) ; } else NSLog(@”sysctl error occured!”) ;


Anyone got a function for disk space or remaining disk space?


getmntinfo(3), getfsstat(2) and statfs(2) will give you information about mounted file systems.

I had to fix the +machineType method. It was buggy. For one, gestaltUserVisibleMachineName returns a Pascal string, so it may not be zero-terminated, and there’s a length byte at the start. I’m surprised the original code even worked, because the dictionary couldn’t possibly match on the string with the length byte at the start.

Also, the code was comparing an OSErr against NIL, which isn’t good style, so I changed that to noErr for correctness’ sake.

Finally, I added the Mac Mini, because that’s what I’m running on. Anyone have other Mac names? This seems to be missing a huge bunch of the Intel Macs…

– UliKusterer

gestaltUserVisibleMachineName seems to be undefined on Mac OS X 10.5 in 64-bit mode (Gestalt() returns gestaltUndefSelectorErr). Is anyone aware of a 64-bit-safe replacement?

Oh, of course. sysctlbyname() works:

char modelBuffer[256]; size_t sz = sizeof(modelBuffer); if (0 == sysctlbyname(“hw.model”, modelBuffer, &sz, NULL, 0)) { modelBuffer[sizeof(modelBuffer) - 1] = 0; printf(“%s”, modelBuffer); }

A (slightly) more orderly and up-to-date list of Mac names is found at MacintoshModels.

Same solution as previous, but avoiding a fixed buffer.

// Return an autoreleased string containing this system’s model name, // e.g., “MacBookPro5,5”, or nil if we were unable to determine the model // name.

NSString * GetModelString() { NSString * modelString = nil; int modelInfo[2] = { CTL_HW, HW_MODEL }; size_t modelSize;

if (sysctl(modelInfo,
           NULL, 0) == 0)
    void * modelData = malloc(modelSize);
    if (modelData)
        if (sysctl(modelInfo,
                   NULL, 0) == 0)
            modelString = [NSString stringWithUTF8String:modelData];

return modelString; }

In order to get the machine name I use this format:

OSErr err;
StringPtr machineNamePascal = NULL;
err = Gestalt(gestaltUserVisibleMachineName, (SInt32 *)&machineNamePascal);
NSString *machineName;
if(err == noErr)
    machineName = [(NSString *)CFStringCreateWithPascalString(NULL,

Can anyone tell me why I don’t need to free machineNamePascal?



Yet another interesting C snippet showing how to retrieve hardware information on Mac OS X.


C snippet posted by Guiyon on Jun 12, 2009, 09:38 AM at:

“Getting Hardware Details from Objective-C”,

compile with:

gcc -Wall -O3 -x objective-c -fobjc-exceptions -fnested-functions -framework Foundation \ -framework CoreFoundation -framework IOKit -o machardwareinfo machardwareinfo.c


Should run on Mac OS X 10.4 and later.


ioreg -l -w0 | awk -F’= ‘ ‘/”IOCPUID” = /{print $2; exit}’ ioreg -l -w0 | grep ‘device_type’ | grep -E -i ‘cpu|processor’

See also:


#import <Foundation/Foundation.h> #import <IOKit/IOKitLib.h>

#include <sys/sysctl.h> #include <sys/resource.h> #include <sys/vm.h>

/* ADDED !!! */ #ifndef MAC_OS_X_VERSION_10_4 #define MAC_OS_X_VERSION_10_4 1040 #endif

#if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4) #define MAC_OS_X_VERSION_10_5_AND_LATER 1 #define MATCHSTR “processor” #else #define MAC_OS_X_VERSION_10_5_AND_LATER 0 #define MATCHSTR “cpu” #endif

#ifndef KERN_OSVERSION //#define KERN_OSVERSION 8110 #define KERN_OSVERSION “Darwin” #endif

static void objc_println( NSString* format, … ); static void printSysctlInfo( void ); static NSDictionary* getCpuIds( void ); static NSString* getPlatformSerialNumber( void );

int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

objc_println(@”Beginning system data collection…”);

NSProcessInfo* pinfo = [NSProcessInfo processInfo];

objc_println( @”NSProcessInfo:” ); objc_println( @”\tProcess Name: %@”, [pinfo processName] ); objc_println( @”\tPID: %d”, [pinfo processIdentifier] ); objc_println( @”\tProcess GUID: %@”, [pinfo globallyUniqueString] ); objc_println( @”\tOS Version: %@”, [pinfo operatingSystemVersionString] ); if (MAC_OS_X_VERSION_10_5_AND_LATER) /* ADDED !!! */ { objc_println( @”\tTotal Processors: %d”, [pinfo processorCount] ); objc_println( @”\tActive Processors: %d”, [pinfo activeProcessorCount] ); objc_println( @”\tTotal RAM: %ull bytes”, [pinfo physicalMemory] ); }else { objc_println( @”\tTotal Processors: [not available]”); objc_println( @”\tActive Processors: [not available]”); objc_println( @”\tTotal RAM: XXX bytes [not available]”); }


objc_println( @”IOKit:” ); NSDictionary cpuInfo = getCpuIds(); NSArray keys = cpuInfo allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];

/* for( id key in keys ) { objc_println( @”\t%@ has ID: 0x%8.8x”, key, [([[NSNumber*)[cpuInfo objectForKey: key] unsignedIntValue] ); } */

/* ADDED !!! / / more portable code than: for( id key in keys ) { … / int i, num; num = [keys count]; for (i = 0; i < num; i++) { objc_println( @”\t%@ has CPU ID:\n\tdec: %d\n\thex: 0x%8.8x”, [keys objectAtIndex: i], \ [(NSNumber)[cpuInfo objectForKey: [keys objectAtIndex: i]] unsignedIntValue], [(NSNumber*)[cpuInfo objectForKey: [keys objectAtIndex: i]] unsignedIntValue] ); }

objc_println( @”\tSerial Number: %@”, getPlatformSerialNumber() );

/* [pool drain]; */ [pool release];

return 0; }

static void objc_println( NSString* format, … ) { va_list args;

if (![format hasSuffix: @”\n”]) { format = [format stringByAppendingString: @”\n”]; }

va_start (args, format); NSString *body = [[NSString alloc] initWithFormat: format arguments: args]; va_end (args);

fprintf(stderr,”%s”,[body UTF8String]);

[body release]; }

static void printSysctlInfo( void ) { objc_println( @”sysctl:” );

int mib[2]; size_t len = 0; char *rstring = NULL; unsigned int rint = 0;

/* Setup the MIB data */ mib[0] = CTL_KERN; mib[1] = KERN_OSTYPE;

/* Get the length of the string */ sysctl( mib, 2, NULL, &len, NULL, 0 );

/* Now allocate space for the string and grab it */ rstring = malloc( len ); sysctl( mib, 2, rstring, &len, NULL, 0 ); objc_println( @”\tkern.ostype: %s”, rstring );

/* Make sure we clean up afterwards! */ free( rstring ); rstring = NULL;

/* Get the kernel release number */ mib[0] = CTL_KERN; mib[1] = KERN_OSRELEASE; sysctl( mib, 2, NULL, &len, NULL, 0 ); rstring = malloc( len ); sysctl( mib, 2, rstring, &len, NULL, 0 ); objc_println( @”\tkern.osrelease: %s”, rstring ); free( rstring ); rstring = NULL;

/* Get the Mac OS X Build number */ mib[0] = CTL_KERN; mib[1] = KERN_OSVERSION; sysctl( mib, 2, NULL, &len, NULL, 0 ); rstring = malloc( len ); sysctl( mib, 2, rstring, &len, NULL, 0 ); objc_println( @”\tkern.osversion: %s”, rstring ); free( rstring ); rstring = NULL;

mib[0] = CTL_HW; mib[1] = HW_MODEL; sysctl( mib, 2, NULL, &len, NULL, 0 ); rstring = malloc( len ); sysctl( mib, 2, rstring, &len, NULL, 0 ); objc_println( @”\thw.model: %s”, rstring ); free( rstring ); rstring = NULL;

sysctlbyname( “machdep.cpu.brand_string”, NULL, &len, NULL, 0 ); rstring = malloc( len ); sysctlbyname( “machdep.cpu.brand_string”, rstring, &len, NULL, 0 ); objc_println( @”\tmachdep.cpu.brand_string: %s”, rstring ); free( rstring ); rstring = NULL;

mib[0] = CTL_HW; mib[1] = HW_CPU_FREQ; len = sizeof( rint ); sysctl( mib, 2, &rint, &len, NULL, 0 ); objc_println( @”\thw.cpufrequency: %u”, rint ); }

static NSString* getPlatformSerialNumber( void ) { io_registry_entry_t rootEntry = IORegistryEntryFromPath( kIOMasterPortDefault, “IOService:/” ); CFTypeRef serialAsCFString = NULL;

serialAsCFString = IORegistryEntryCreateCFProperty( rootEntry, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0);

IOObjectRelease( rootEntry ); return (NULL != serialAsCFString) ? [(NSString*)serialAsCFString autorelease] : nil; }

static NSDictionary* getCpuIds( void ) { NSMutableDictionary* cpuInfo = [[NSMutableDictionary alloc] init]; CFMutableDictionaryRef matchClasses = NULL; kern_return_t kernResult = KERN_FAILURE; mach_port_t machPort; io_iterator_t serviceIterator;

io_object_t cpuService;

kernResult = IOMasterPort( MACH_PORT_NULL, &machPort ); if( KERN_SUCCESS != kernResult ) { printf( “IOMasterPort failed: %d\n”, kernResult ); }

/* ADDED !!! / matchClasses = IOServiceNameMatching( MATCHSTR ); / matchClasses = IOServiceNameMatching( “processor” ); */

if( NULL == matchClasses ) { printf( “IOServiceMatching returned a NULL dictionary” ); }

kernResult = IOServiceGetMatchingServices( machPort, matchClasses, &serviceIterator ); if( KERN_SUCCESS != kernResult ) { printf( “IOServiceGetMatchingServices failed: %d\n”, kernResult ); }

while( (cpuService = IOIteratorNext( serviceIterator )) ) { CFTypeRef CPUIDAsCFNumber = NULL; io_name_t nameString;
IORegistryEntryGetNameInPlane( cpuService, kIOServicePlane, nameString );

CPUIDAsCFNumber = IORegistryEntrySearchCFProperty( cpuService, 
                                                  CFSTR( "IOCPUID" ), 

if( NULL != CPUIDAsCFNumber ) {
  NSString* cpuName = [NSString stringWithCString:nameString];
  [cpuInfo setObject:(NSNumber*)CPUIDAsCFNumber forKey:cpuName];

if( NULL != CPUIDAsCFNumber ) {
  CFRelease( CPUIDAsCFNumber );
}   }

IOObjectRelease( serviceIterator );

return [cpuInfo autorelease]; }

Note that you can make use of the system_profiler command line to gather full information about the system. Its -xml option generates a plist file that can be used easily in any Cocoa application:

 system_profiler reports on the hardware and software configuration of the system.  It can generate plain text reports or XML reports which can be opened with

 -xml                Generates a report in XML format.  If the XML report is redirected to a file with a ".spx" suffix that file can be opened with System

 -listDataTypes      Lists the available datatypes.

 -detailLevel level  Specifies the level of detail for the report:

                     mini          report with no personal information

                     basic         basic hardware and network information

                     full          all available information