Getting Hardware Details from Objective-C

Discussion in 'Mac Programming' started by Jose Jayan, Jun 12, 2009.

  1. macrumors newbie

    Joined:
    Jun 9, 2009
    #1
    Hi there

    I want to write a cocoa app which will retrieve the following machine details.

    CPU Model,CPU ID
    Machine Name, Machine IP
    Hard Disk Details
    RAM Details
    Operating System


    Could you people please advice me on this(Instead of calling system_profiler from terminal)?
     
  2. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    There is no Cocoa API for this. You have to call into Carbon (if you can find an API for it: I haven't looked) or do what you have already ruled out: call out to the system_profiler command line.
     
  3. macrumors G5

    gnasher729

    Joined:
    Nov 25, 2005
    #3
    Search for "Gestalt".
    Or use the power of Posix to call system_profiler from your application and read its output.
     
  4. thread starter macrumors newbie

    Joined:
    Jun 9, 2009
    #4
    But neither the Gestalt or system_profiler revealed the CPU Serial ID or MotherBoardID(Serial Number).
    Also tried IOREG from terminal.
     
  5. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #5
    Google gave me this in, like, 3 seconds: Google answer. Seriously: search.
     
  6. macrumors 6502a

    Joined:
    Mar 19, 2008
    Location:
    North Shore, MA
    #6
    Depending on exactly what you need, you have several options other than relying on a dying API or brute-force searching through the output of an NSTask. For example, both the NSProcessInfo and the sysctl API can provide a significant amount of information about a system (and, in the case of sysctl, it's pretty portable). If you need even more detailed information there is also IOKit and, using that, you can grab everything down to each individual CPU's ID.

    Just the file as "HWInfo.m" and compile it using:
    Code:
    gcc -framework "Foundation" -framework "IOKit" -o HWInfo HWInfo.m

    Edit: Updated with code for grabbing CPUIDs and Serial Number using IOKit
    Edit 2: Significantly condensed down the code for grabbing the serial number. It's just grabbing the root entry so setting up a matching dictionary, etc. is just overkill.
    Edit 3: Last edit, I promise! Moved the sysctl stuff into its own function to make it a bit easier to parse. Replaced NSLog with objc_println.

    Here is an example using NSProcessInfo, sysctl and the IOKit APIs:
    Code:
    #import <Foundation/Foundation.h>
    #import <IOKit/IOKitLib.h>
    
    #include <sys/sysctl.h>
    #include <sys/resource.h>
    #include <sys/vm.h>
    
    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] );
      objc_println( @"\tTotal Processors: %d", [pinfo processorCount] );
      objc_println( @"\tActive Processors: %d", [pinfo activeProcessorCount] );
      objc_println( @"\tTotal RAM: %ull bytes", [pinfo physicalMemory] );
      
      printSysctlInfo();
      
      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] );
      }
      
      objc_println( @"\tSerial Number: %@", getPlatformSerialNumber() );
      
      [pool drain];
      
      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 );
      }
      
      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, 
                                                          kIOServicePlane,
                                                          CFSTR( "IOCPUID" ), 
                                                          kCFAllocatorDefault,
                                                          kIORegistryIterateRecursively);
        
        if( NULL != CPUIDAsCFNumber ) {
          NSString* cpuName = [NSString stringWithCString:nameString];
          [cpuInfo setObject:(NSNumber*)CPUIDAsCFNumber forKey:cpuName];
        }
        
        if( NULL != CPUIDAsCFNumber ) {
          CFRelease( CPUIDAsCFNumber );
        }
      }
      
      IOObjectRelease( serviceIterator );
      
      return [cpuInfo autorelease];
    }
     
  7. macrumors 6502a

    Joined:
    Oct 13, 2007
    #7

Share This Page