/*
 * SM(BIOS) UTility
 *
 * One of the source code examples from MOXiI 2, Volume II
 *
 * Dumps the AppleSMBIOS property from the IORegistry in a nice and
 * more human readable format.
 *
 *
 * To compile:
 *  	gcc smut.c -o bios -framework IOKit -framework CoreFoundation
 *
 * (will compile <del>cleanly</del> just fine, maybe a warning or two.. I promise)
 *
 * License: Free to use. But don't forget to give credit where due if you
 *          found this useful.
 *
 * (This could actually work on any Intel device with SMBIOS - feel free
 *  to port this to Linux, if there isn't have something for that already)
 *
 */

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

typedef unsigned char  UInt8 ;
typedef unsigned short UInt16 ;
typedef unsigned int  UInt32 ;
typedef unsigned long long  UInt64 ;


const char ver[] =
	{"@(#) PROGRAM: smut 1.0 \tPROJECT: Jtools"}; // for what(1)

#include "SMBIOS.h" // updated from Apple's SMBIOS project (q.v. http://newosxbook.com/code/listings/SMBIOS.h)

#define IOKIT	// to unlock device/device_types..
#include <device/device_types.h> // for io_name, io_string
#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>


// from IOKit/IOKitLib.h
extern const mach_port_t kIOMasterPortDefault;

// from IOKit/IOTypes.h
//typedef mach_port_t     io_object_t;
typedef io_object_t     io_connect_t;
typedef io_object_t     io_enumerator_t;
typedef io_object_t     io_iterator_t;
typedef io_object_t     io_registry_entry_t;
typedef io_object_t     io_service_t;


kern_return_t
IOServiceGetMatchingServices(
        mach_port_t     masterPort,
        CFDictionaryRef matching,
        io_iterator_t * existing );

CFMutableDictionaryRef
IOServiceMatching(
        const char *    name );


// typedef unsigned long IOOptionBits;
kern_return_t
IORegistryEntryCreateCFProperties(
        io_registry_entry_t     entry,
        CFMutableDictionaryRef * properties,
        CFAllocatorRef          allocator,
        IOOptionBits            options );


CFTypeRef
IORegistryEntryCreateCFProperty(
        io_registry_entry_t     entry,
        CFStringRef             key,
        CFAllocatorRef          allocator,
        IOOptionBits            options );


// Globals go here:
int g_verbose = 0;
#define vprintf if (g_verbose) printf


int hexDump (unsigned char *Buf, int Len)
{
        int i = 0 ;

        fprintf (stdout, "0x%04X: ", 0);
        for (i = 0 ; i < Len; i ++) {
                if (i && (i % 8 == 0)) {
                        fprintf(stdout,"\t%c%c%c%c%c%c%c%c\n",
                        isprint(Buf[i-8]) ? Buf[i-8] : '.',
                        isprint(Buf[i-7]) ? Buf[i-7] : '.',
                        isprint(Buf[i-6]) ? Buf[i-6] : '.',
                        isprint(Buf[i-5]) ? Buf[i-5] : '.',
                        isprint(Buf[i-4]) ? Buf[i-4] : '.',
                        isprint(Buf[i-3]) ? Buf[i-3] : '.',
                        isprint(Buf[i-2]) ? Buf[i-2] : '.',
                        isprint(Buf[i-1]) ? Buf[i-1] : '.');
                        
                        fprintf (stdout, "0x%4X: ", i);
                }
                fprintf(stdout, "0x%02X ", (unsigned char) Buf[i]);
        }

        fprintf(stdout,"\n");
        return 0;
} // hexDump


CFDataRef getProp(io_service_t	Service, char *IOPropertyName)
{

  
  CFMutableDictionaryRef propertiesDict;


  if (IOPropertyName)
	{
  		CFStringRef	cfStrPropertyName = CFStringCreateWithCString (kCFAllocatorDefault, // CFAllocatorRef alloc,
						    IOPropertyName, // const char *cStr, 
						    kCFStringEncodingASCII); // CFStringEncoding encoding ); 

		CFTypeRef  propertyRef = IORegistryEntryCreateCFProperty(Service, // io_registry_entry_t     entry,
							  cfStrPropertyName, // CFStringRef	key,
							  kCFAllocatorDefault, // CFAllocatorRef allocator,
							  0);  // IOOptionBits options
						

		
		if (!propertyRef)
			{
				printf("Property %s not found\n", IOPropertyName);
				return NULL;
			}

		if (CFGetTypeID(propertyRef) == CFStringGetTypeID()) {
			   int len = CFStringGetLength(propertyRef);
			   printf("LEN IS %d\n", len);
			   const char* str = CFStringGetCStringPtr(propertyRef, kCFStringEncodingASCII);
			   int i = 0;
			   for (i = 0 ; i < len; i ++) putchar (str[i]);
			   printf("\n");
			}
		if (CFGetTypeID(propertyRef) == CFDataGetTypeID()) {
			   return (propertyRef);

			   

		}

	}

   else {
  kern_return_t kr = IORegistryEntryCreateCFProperties( Service,
                                                    &propertiesDict,
                                                    kCFAllocatorDefault,
                                                    kNilOptions );

    CFDataRef xml = CFPropertyListCreateXMLData(kCFAllocatorDefault,
                                                (CFPropertyListRef)propertiesDict);
    if (xml) {
        write(1, CFDataGetBytePtr(xml), CFDataGetLength(xml));
        CFRelease(xml);
	}

	} // end else
	return 0;
}

char *getSMBString (unsigned char *SMBElement,
	            unsigned int  stringNum)
{

  struct SMBStructHeader *sh = (struct SMBStructHeader *) SMBElement;
  int s = 1;
  char *theString = (char *)(SMBElement + sh->length);
  int off = 0 ;
  
  while (s < stringNum)
	{
	   while (theString[0])  { theString++;}
	   // Now points to NULL, so advance.
	   theString++;
	   s++;;
	}

  if (theString[0]) {return (theString);} // If this is the n-th string
  else return( "");
  
  

}

const char *bootStatusToText (int Use) {
	switch (Use){

	case 0: return "no errors detected";
	case 1: return "no bootable media";
	case 2: return "normal OS failed to load";
	case 3: return "firmware detected failure";
	case 4: return "OS detected failure";
	case 5: return "User requested boot";
	case 6: return "system security violation";
	case 7: return "previously requested image";
	case 8: return "watchdog timer expiration";
	default: return "unknown/reserved";

	}
} // bootStatusToText
const char *memLocToText (int Use) {
	switch (Use){

	case 1: return "other";
	case 2: return "unnknown";
	case 3: return "system board/motherboard";
	case 4: return "ISA add-on";
	case 5: return "EISA add-on";
	case 6: return "PCI add-on";
	case 7: return "MCA add-on";
	case 8: return "PCMCIA add-on";
	case 9: return "proprietary add-on";
	default: return "?!";
	}
} // memLoc

const char *memUseToText (int Use) {
	switch (Use){

	case 1: return "other";
	case 2: return "unnknown";
	case 3: return "system memory";
	case 4: return "video memory";
	case 5: return "flash memory";
	case 6: return "NVRAM";
	case 7: return "cache memory";
	default: return "?!";

	}

} // memUs

const char *enclosureTypeToText (int Type){
	switch (Type)
	{
	case 1: return "other";
	case 2: return "unnknown";
	case 3: return "dekstop";
	case 4: return "low profile desktop";
	case 5: return "pizza box";
	case 6: return "mini tower";
	case 7: return "tower";
	case 8: return "portable";
	case 9: return "laptop";
	case 10: return "notebook";
	case 11: return "handheld";
	case 12: return "docking station";
	case 13: return "all in one";
	case 14: return "sub notebook";
	default: return "Too many codes - J hasn't filled all";
	} // 

} // deviceTypeToText
const char *deviceTypeToText (int Type){
	switch (Type)
	{
	case 1: return "other";
	case 2: return "unnknown";
	case 3: return "video";
	case 4: return "SCSI";
	case 5: return "Ethernet";
	case 6: return "Token Ring...";
	case 7: return "Sound";
	case 8: return "PATA";
	case 9: return "SATA";
	case 10: return "SAS";
	default: return "?!";
	} // 

} // deviceTypeToText

ssize_t	parseSMBIOSStruct(unsigned char *Bytes, int Offset, int Len)
{
	// An SMBIOSStruct starts with a header, defining its type and length:
        // struct SMBStructHeader {
    	//	SMBByte    type;
   	//      SMBByte    length;
   	//	SMBWord    handle;
	// };

	
	struct SMBStructHeader *ssh = (struct SMBStructHeader *)(Bytes +Offset);

	vprintf("%d: Header for type %d, Length %u bytes, handle %hd\n", 
		 Offset,
		 Bytes[Offset],
	  	 Bytes[Offset+1],
		(*(SMBWord *) (Bytes + Offset + 2)));
		

	// Advancing however many bytes are specified in the length field will
	// bring us to the beginning of the string set - or the first of the 
	// double-NULL byte terminator

	unsigned char *current = Bytes + Offset;
        SMBByte len = ssh->length; //current[1]; // Can also get this via struct.

	printf("0x%x:", Offset);
	switch (Bytes[Offset]) // which is the type
	{
		case  kSMBTypeBIOSInformation:            // =  0,
		   {
#if 0
struct SMBBIOSInformation {
    SMB_STRUCT_HEADER               // Type 0
    SMBString  vendor;              // BIOS vendor name
    SMBString  version;             // BIOS version
    SMBWord    startSegment;        // BIOS segment start
    SMBString  releaseDate;         // BIOS release date
    SMBByte    romSize;             // (n); 64K * (n+1) bytes
    SMBQWord   characteristics;     // supported BIOS functions
};


#endif
		    printf("BIOS Information:\n");
		  struct SMBBIOSInformation *bi = (struct SMBBIOSInformation *) current;
			printf("\tVendor: %s\n",  getSMBString((void *) current, bi->vendor));
			printf("\tVersion: %s\n",  getSMBString((void *) current, bi->version));
			printf("\tRelease Date: %s\n",  getSMBString((void *) current, bi->releaseDate));


			}
		
		    break;
	
		case  kSMBTypeSystemInformation:          // =   1,
		    printf("System Information:\n");
		    
		    struct SMBSystemInformation *si = (struct SMBSystemInformation *) current;
		    printf("\tManufacturer: %s\n", getSMBString (current, si->manufacturer));
		    printf("\tProduct Name: %s\n", getSMBString (current, si->productName));
		    printf("\tVersion: %s\n", getSMBString (current, si->version));
		    printf("\tSerial #: %s\n", getSMBString (current, si->serialNumber));
		    
		    break;
	
		case  kSMBTypeBaseBoard:                  // =   2,
		    printf("Base Board:\n");

		{ 
			struct SMBBaseBoard *bb= (struct SMBBaseBoard *) current;
			
			printf("\tManufacturer: %s\n", getSMBString((void *) current, bb->manufacturer));
			printf("\tProduct: %s\n", getSMBString((void *) current, bb->product));
			printf("\tVersion: %s\n", getSMBString((void *) current, bb->version));
			printf("\tSerial #: %s\n", getSMBString((void *) current, bb->serialNumber));
			printf("\tLocation: %s\n", getSMBString((void *) current, bb->locationInChassis));

		}


		    break;
		case  kSMBTypeSystemEnclosure:            // =   3,
		   {
		    printf("System Enclosure:\n");
		struct SMBSystemEnclosure *se = (struct SMBSystemEnclosure *) current;
		printf("\tManufacturer: %s\n", getSMBString((void *)current, se->manufacturer));
		printf("\tVersion: %s\n", getSMBString((void*)current, se->version));
		printf("\tSerial #: %s\n", getSMBString((void*)current, se->serialNumber));
		printf("\tType: %s\n", enclosureTypeToText(se->type & 0x7f));

#if 0
struct SMBSystemEnclosure {
    SMB_STRUCT_HEADER               // Type 3
    SMBString  manufacturer;
    SMBByte    type;
    SMBString  version;
    SMBString  serialNumber;
    SMBString  assetTagNumber;
    SMBByte    bootupState;
    SMBByte    powerSupplyState;
    SMBByte    thermalState;
    SMBByte    securityStatus;
    SMBDWord   oemDefined;

#endif
		}
		    break;
		case  kSMBTypeProcessorInformation:       // =   4,
		    printf("Processor Information:\n");
	
		    struct SMBProcessorInformation *pi = (struct SMBProcessorInformation *) (Bytes + Offset);
	
		    printf("\tSocket designation: %s\n", getSMBString(Bytes + Offset,
								      pi->socketDesignation));
		    printf("\tManufacturer: %s\n", getSMBString(Bytes + Offset, pi->manufacturer));
		    printf("\tVersion: %s\n", getSMBString(Bytes + Offset, pi->processorVersion));
		    printf("\tSerial #: %s\n", getSMBString(Bytes + Offset, pi->serialNumber));
		    printf("\tClocks: External %f Ghz\tMaximum: %f Ghz\tCurrent: %f Ghz\n",
			    ((float)pi->externalClock / 1000),
			    ((float)pi->maximumClock / 1000),
			    ((float)pi->currentClock / 1000));


		    printf("\tCaches: L1: %d\t L2: %d\tL3: %d\n",
			  pi->L1CacheHandle,
			  pi->L2CacheHandle,
			  pi->L3CacheHandle);

#if 0
struct SMBProcessorInformation {
    // 2.0+ spec (26 bytes)
    SMB_STRUCT_HEADER               // Type 4
    SMBString  socketDesignation;
    SMBByte    processorType;       // CPU = 3
    SMBByte    processorFamily;     // processor family enum
    SMBString  manufacturer;
    SMBQWord   processorID;         // based on CPUID
    SMBString  processorVersion;
    SMBByte    voltage;             // bit7 cleared indicate legacy mode
    SMBWord    externalClock;       // external clock in MHz
    SMBWord    maximumClock;        // max internal clock in MHz
    SMBWord    currentClock;        // current internal clock in MHz
    SMBByte    status;
    SMBByte    processorUpgrade;    // processor upgrade enum
    // 2.1+ spec (32 bytes)
    SMBWord    L1CacheHandle;
    SMBWord    L2CacheHandle;
    SMBWord    L3CacheHandle;
    // 2.3+ spec (35 bytes)
    SMBString  serialNumber;
    SMBString  assetTag;
    SMBString  partNumber;
};
#endif


		    break;
		case  kSMBTypeMemoryModule:               // =   6,
		    printf("Memory Module:\n");
		    break;
		case  kSMBTypeCacheInformation:           // =   7,
			
			{
			struct SMBCacheInformation *ci = (struct SMBCacheInformation *) current;
		    printf("Cache Information (#%d):\n", ci->header.handle);
		    printf("\tSocket designation: %s\n", getSMBString((unsigned char *)ci, ci->socketDesignation));
		    printf("\tSize: %d/%dKB\n", ci->installedSize, ci->maximumCacheSize);
		if (ci->cacheSpeed) { printf("\tSpeed: %d\n", ci->cacheSpeed);}
		
#if 0

struct SMBCacheInformation {
    SMB_STRUCT_HEADER               // Type 7
    SMBString  socketDesignation;
    SMBWord    cacheConfiguration;
    SMBWord    maximumCacheSize;
    SMBWord    installedSize;
    SMBWord    supportedSRAMType;
    SMBWord    currentSRAMType;
    SMBByte    cacheSpeed;
    SMBByte    errorCorrectionType;
    SMBByte    systemCacheType;
    SMBByte    associativity;
};
#endif

		}
		    break;
		case  kSMBTypeSystemSlot:                 // =   9,
		    printf("System Slot:\n");
		
		    struct SMBSystemSlot *ss = (struct SMBSystemSlot *) current;
		    printf("\tDesignation: %s\n", getSMBString(current, ss->slotDesignation));

#if 0
struct SMBSystemSlot {
    // 2.0+ spec (12 bytes)
    SMB_STRUCT_HEADER               // Type 9
    SMBString   slotDesignation;
    SMBByte     slotType;
    SMBByte     slotDataBusWidth;
    SMBByte     currentUsage;
    SMBByte     slotLength;
    SMBWord     slotID;
    SMBByte     slotCharacteristics1;
    // 2.1+ spec (13 bytes)
    SMBByte     slotCharacteristics2;
};
#endif

		    break;
		case  kSMBTypePhysicalMemoryArray:        // =  16,
			{
		    printf("Physical Memory Array:\n");

#if 0
struct SMBPhysicalMemoryArray {
    // 2.1+ spec (15 bytes)
    SMB_STRUCT_HEADER               // Type 16
    SMBByte    physicalLocation;    // physical location
    SMBByte    arrayUse;            // the use for the memory array
    SMBByte    errorCorrection;     // error correction/detection method
    SMBDWord   maximumCapacity;     // maximum memory capacity in kilobytes
    SMBWord    errorHandle;         // handle of a previously detected error
    SMBWord    numMemoryDevices;    // number of memory slots or sockets
};

#endif
			struct SMBPhysicalMemoryArray * pma =  (struct SMBPhysicalMemoryArray *) current;

			printf("\tPhysical Location: %d (%s)\n", pma->physicalLocation, memLocToText( pma->physicalLocation ));
			printf("\tArray Use: %d (%s)\n", pma->arrayUse, memUseToText(pma->arrayUse));
			printf("\tMaximum Capacity: %dGB\n", pma->maximumCapacity/ (1024*1024));

			}
		    break;

		case  kSMBTypeMemoryDevice:               // =  17,
		    printf("Memory Device:\n");
		    struct SMBMemoryDevice *md = (struct SMBMemoryDevice *) (Bytes + Offset);
		
		    printf("\tSize: %d %s\tSpeed: %d Mhz",
			    md->memorySize & 0x7FFF,
			    (md->memorySize & 0x8000 ? "KB" : "MB"),
			    md->memorySpeed);

		    printf("\tDevice Locator: %s\tBank Locator: %s\n",	
			   getSMBString (Bytes + Offset, md->deviceLocator),
			   getSMBString (Bytes + Offset, md->bankLocator));
		    printf("\tManufacturer: %s\tAsset Tag: %s\n",
			   getSMBString (Bytes + Offset, md->manufacturer),
			   getSMBString (Bytes + Offset, md->assetTag));
		    printf("\tSerial #: %s\tPart #: %s\n",
			   getSMBString (Bytes + Offset, md->serialNumber),
			   getSMBString (Bytes + Offset, md->partNumber));
	
		

#if 0
struct SMBMemoryDevice {
    // 2.1+ spec (21 bytes)
    SMB_STRUCT_HEADER               // Type 17
    SMBWord    arrayHandle;         // handle of the parent memory array
    SMBWord    errorHandle;         // handle of a previously detected error
    SMBWord    totalWidth;          // total width in bits; including ECC bits
    SMBWord    dataWidth;           // data width in bits
    SMBWord    memorySize;          // bit15 is scale, 0 = MB, 1 = KB
    SMBByte    formFactor;          // memory device form factor
    SMBByte    deviceSet;           // parent set of identical memory devices
    SMBString  deviceLocator;       // labeled socket; e.g. "SIMM 3"
    SMBString  bankLocator;         // labeled bank; e.g. "Bank 0" or "A"
    SMBByte    memoryType;          // type of memory
    SMBWord    memoryTypeDetail;    // additional detail on memory type
    // 2.3+ spec (27 bytes)
    SMBWord    memorySpeed;         // speed of device in MHz (0 for unknown)
    SMBString  manufacturer;
    SMBString  serialNumber;
    SMBString  assetTag;
    SMBString  partNumber;
};
#endif

		    break;
		case  kSMBType32BitMemoryErrorInfo:       // =  18,
		    printf("32-Bit Memory Error Info:\n");
		    break;
		case jSMBTypePortableBatteryInfo:	// == 22
			{
		     printf("Portable Battery Info:\n");
		struct SMBPortableBatteryInformation  *bi = (struct SMBPortableBatteryInformation *) current;

		    printf("\tManufacturer: %s %d\n", getSMBString (current, bi->manufacturer), si->manufacturer);
		    printf("\tSerial #: %s\n", getSMBString (current, bi->serialNumber));
		    printf("\tName: %s\n", getSMBString (current, bi->deviceName));
		    printf("\tDesign Capacity: %d\n",bi->designCapacity);
		    printf("\tDesign Voltage: %d\n",bi->designVoltage);
			}
		    break;

		case jSMBTypeManagementDeviceComponentInfo:	// == 35
		     printf("Management Device Component Info:\n");
		    break;

		case jSMBTypeManagementDeviceThresholdData:	// == 36
		     printf("Management Device Threshold Data:\n");
		    break;

		case jSMBTypeOnboardDevicesExtendedInfo:	// = 41
		     printf("Onboard Devices Extended Info:\n");
			{
		struct SMBOnboardDevicesExtendedInformation  *odei = (struct SMBOnboardDevicesExtendedInformation *)				current;
			printf("\tReference Designation : %s\tType: %s (%s)\n",
				getSMBString(current, odei->referenceDesignation), 
				deviceTypeToText(odei->deviceType & 0x7f),
				(odei->deviceType &0x80 ? "enabled" : "disabled"));

#if 0
struct SMBOnboardDevicesExtendedInformation {
        SMB_STRUCT_HEADER       
        SMBByte referenceDesignation;
        SMBByte deviceType;
        SMBByte deviceTypeInstance;
        SMBWord SegmentGroupNumber;
        SMBByte busNumber;
        SMBByte bitField;
};
#endif
			}
			
			break;

		case jSMBTypeGroupAssociations: // 14
		     printf("Group Associations\n");
		     break;
		case  jSMBTypeIMIDeviceInfo:	//  38
			printf("IPMI Device Information\n");
			break;

		case  kSMBType64BitMemoryErrorInfo:       // =  33,
		    printf("64-Bit Memory Error Info:\n");
		    break;

	
		// J's Additions:
		case 8: // Port Connector Information: (7.9)
		    printf("Port Connector Information\n");
		    struct SMBPortConnectorInformation *pci =
			(struct SMBPortConnectorInformation *) (Bytes + Offset);
		    
		    printf("\tInternal Reference Designator: %s\tType: %d\n",
			   getSMBString(Bytes + Offset , pci->InternalReferenceDesignator),
			   pci->InternalConnectorType);

		    printf("\tExternal Reference Designator: %s\tType: %d\n",
			   getSMBString(Bytes + Offset , pci->ExternalReferenceDesignator),
			   pci->ExternalConnectorType);


		    break;
		case 10: // On Board Device Information (obsolete in 2.7)
		    // This is obsolete, but also different in that the
		    // length is longer than the average

		   {
		    int numDevices = (current[1] -4) /2;
		    printf("On Board Device Information (%d Devices):\n", numDevices);
		    int d = 0;
		    for (d = 1 ; d <= numDevices;  d++)
			{
			   printf("\t%d: %s\n",
				  d, getSMBString (current, 
						   *(current + 5 + 2 * (d-1)))); 
			}
		   
		   
			}
		    break;
		case 11: // OEM Strings
		    printf("OEM Strings: (%d Strings)\n", current[0x4]);
		    Offset += 5;
		    int s = 0;

		    while (Bytes[Offset])
			{
				printf("\tString %d: ", s);
				while (Bytes[Offset]) {
					if ((Bytes[Offset] == ' ') || ispunct (Bytes[Offset]) || (isalnum(Bytes[Offset]))) {
						putchar (Bytes[Offset]);
						}
					else 
						{ 
						   switch (Bytes[Offset])
							{ 
							case 0xa: printf("\\r"); break;
							case 0xd: printf("\\n"); break;

							default:
							printf("\\x%02x", Bytes[Offset]);
							} // end switch (Bytes[Offset]) for case 11
						}
					Offset++;
					} ; // end while
			  	printf("\n");
				s++;
				Offset++;

			}
		 
		    
		    return (Offset+1);
		    break;
		case 12: // System Configuration Options
		    printf("System Configuration Options:\n");
		    
		    break;

		case 13: // BIOS Language Information
	            printf("BIOS Language Information:\n");
		    printf("Installable Languages: %d\n",
				*(current + 0x4));
		    printf("String: %d %s\n", *(current + 0x15), 
					getSMBString (current ,
						*(current+ 0x15)));
		
		    break;

		case jSMBTypeMemoryArrayMappedAddress: // Memory Array Mapped Address
		
		    printf("Memory Array Mapped Address:\n");
	{
		struct SMBMemoryArrayMappedAddress *mama = (struct SMBMemoryArrayMappedAddress *) current;

		printf("\tAddress range: 0x%x-0x%x\n",
			mama->startingAddress,
			mama->endingAddress);




	}
		    break;

		case jSMBTypeSystemBootInfo:	// == 32

		    printf("System Boot Information:\n");
			{
		    struct SMBSystemBootInformation *sbi = (struct SMBSystemBootInfomration *) current;
		
		    int i =0;
		    for (i = 0 ; i < sbi->header.length - 10; i++){


				printf("\tStatus[%d]: %d (%s)\n", i,sbi->BootStatus[i],
					bootStatusToText(sbi->BootStatus[i]));


			}

		    }

		    break;

		case 127: // End of table
			printf("End of Table\n");
			break;;
		/* Apple Specific Structures */
		case  kSMBTypeFirmwareVolume:             // =  128,
		    printf("Firmware Volume:\n");
		    break;
		case  kSMBTypeMemorySPD:                  // =  130,
		    printf("Memory SPD:\n");
			hexDump((void *)current, ssh->length);
		    break;
		case  kSMBTypeOemProcessorType:           // =  131,
		    printf("OEM Processor Type:\n");
		    break;
		case  kSMBTypeOemProcessorBusSpeed:       // =  132
		    printf("Firmware Volume:\n");
		    break;

		case 134: // not sure what this is yet
		    printf("Apple SMC Version (probably - 134)\n");
		 {struct SMBSMCVersion *sv = (struct SMBSMCVersion *) current;
		  printf("\tVersion String: %s\n",  sv->version);}
			hexDump((void *)current, ssh->length);
		    break;
		default:
		
		    printf("Unknown type: %d?! (%d bytes)\n", *current , ssh->length);
			hexDump((void *)current, ssh->length);

		    break;
		};



	Offset += len +1 ; // To get to strings

	if (Bytes[Offset]) Offset--; // If it's the NULL byte terminator, correct.

	while (Bytes[Offset])
	{
		while (Bytes[Offset++]) {};

	}

	// If we're here, we hit two NULLs.

	return (Offset +1 );
}

void parseBIOSData (CFDataRef  BIOSDump)
{
   int len = CFDataGetLength(BIOSDump);
   const char *bytes = alloca (len);
   CFDataGetBytes(BIOSDump, CFRangeMake(0,CFDataGetLength(BIOSDump)), (void*)bytes);
   int i = 0;
   if (g_verbose) {
	printf("Data:\n");

   for (i = 0 ; i < len; i ++)
	 { if (isalnum(bytes[i])) putchar (bytes[i]);
		else putchar ('.');
	 }

	} // end g_verbose

   // Now parse SMBios Structures
   
   for (i = 0; i < len; )
	{
		i = parseSMBIOSStruct((void *)bytes, i, len);
	}

  

}

int main(int argc, char **argv)
{
io_iterator_t deviceList;
io_service_t  device;
io_name_t     deviceName;
io_string_t   devicePath;
char	 *ioPlaneName = "IOService";
char	 *ioClassName = "AppleSMBIOS";
char	 *ioPropertyName = "SMBIOS";
int 	  dev = 0;

kern_return_t kr;

if (argc >1)
{
	if (strcmp(argv[1], "-v") == 0) { g_verbose++;}
  

}

// Iterate over all services matching AppleSMBIOS (only one)
// Note the call to IOServiceMatching, to create the dictionary

kr = IOServiceGetMatchingServices(kIOMasterPortDefault,
			     IOServiceMatching(ioClassName),
			     &deviceList);
if (kr)
{
  fprintf(stderr,"IOServiceGetMatchingServices: error\n");
  exit(1);
}
if (!deviceList) {  fprintf(stderr,"%s - No devices matched\n", ioClassName); exit(2); }

while ( IOIteratorIsValid(deviceList) &&         
    (device = IOIteratorNext(deviceList))) {

 kr = IORegistryEntryGetName(device, deviceName);
 if (kr) 
    {
	fprintf (stderr,"Error getting name for device\n"); 
	IOObjectRelease(device);
	continue;
    }

 kr = IORegistryEntryGetPath(device, ioPlaneName, devicePath);

 if (kr) { 
	// Device does not exist on this plane
	IOObjectRelease(device); 
	continue; 
	}
 

 dev++;
 vprintf("%s\t%s\n",deviceName, devicePath);
 CFDataRef	BIOSDump = getProp(device, ioPropertyName);
		 

	parseBIOSData (BIOSDump);



}

if (device) {
 fprintf (stderr,
  "Iterator invalidated while getting devices. Did hardware configuration change?\n");
}
return kr;
}