From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: Import macOS userland adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106 --- system_cmds/nvram.tproj/nvram.c | 965 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 965 insertions(+) create mode 100644 system_cmds/nvram.tproj/nvram.c (limited to 'system_cmds/nvram.tproj/nvram.c') diff --git a/system_cmds/nvram.tproj/nvram.c b/system_cmds/nvram.tproj/nvram.c new file mode 100644 index 0000000..20d1927 --- /dev/null +++ b/system_cmds/nvram.tproj/nvram.c @@ -0,0 +1,965 @@ +/* + * Copyright (c) 2000-2016 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* +cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +// Prototypes +static void UsageMessage(char *message); +static void ParseFile(char *fileName); +static void ParseXMLFile(char *fileName); +static void SetOrGetOFVariable(char *str); +static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef, + CFTypeRef *valueRef); +static kern_return_t SetOFVariable(char *name, char *value); +static void DeleteOFVariable(char *name); +static void PrintOFVariables(void); +static void PrintOFVariable(const void *key,const void *value,void *context); +static void SetOFVariableFromFile(const void *key, const void *value, void *context); +static void ClearOFVariables(void); +static void ClearOFVariable(const void *key,const void *value,void *context); +static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value); + +static void NVRamSyncNow(char *name); + +// Global Variables +static char *gToolName; +static io_registry_entry_t gOptionsRef; +static bool gUseXML; +static bool gUseForceSync; + +#if TARGET_OS_BRIDGE /* Stuff for nvram bridge -> intel */ +#include +#include + +static kern_return_t LinkMacNVRAMSymbols(void); +static kern_return_t GetMacOFVariable(char *name, char **value); +static kern_return_t SetMacOFVariable(char *name, char *value); +static kern_return_t DeleteMacOFVariable(char *name); + +static bool gBridgeToIntel; +static void *gDL_handle; +static void *gNvramInterface; + +static void (*hostInterfaceInitialize_fptr)(void); +static void *(*createNvramHostInterface_fptr)(const char *handle); +static kern_return_t (*destroyNvramHostInterface_fptr)(void *interface); +static kern_return_t (*getNVRAMVariable_fptr)(void *interface, char *name, char **buffer, uint32_t *size); +static kern_return_t (*setNVRAMVariable_fptr)(void *interface, char *name, char *buffer); +static kern_return_t (*deleteNVRAMVariable_fptr)(void *interface, char *name); +static void (*hostInterfaceDeinitialize_fptr)(void); /* may not need? */ + +#endif /* TARGET_OS_BRIDGE */ + +int main(int argc, char **argv) +{ + long cnt; + char *str, errorMessage[256]; + kern_return_t result; + mach_port_t masterPort; + int argcount = 0; + + // Get the name of the command. + gToolName = strrchr(argv[0], '/'); + if (gToolName != 0) gToolName++; + else gToolName = argv[0]; + + result = IOMasterPort(bootstrap_port, &masterPort); + if (result != KERN_SUCCESS) { + errx(1, "Error getting the IOMaster port: %s", + mach_error_string(result)); + } + + gOptionsRef = IORegistryEntryFromPath(masterPort, "IODeviceTree:/options"); + if (gOptionsRef == 0) { + errx(1, "nvram is not supported on this system"); + } + + for (cnt = 1; cnt < argc; cnt++) { + str = argv[cnt]; + if (str[0] == '-' && str[1] != 0) { + // Parse the options. + for (str += 1 ; *str; str++) { + switch (*str) { + case 'p' : +#if TARGET_OS_BRIDGE + if (gBridgeToIntel) { + fprintf(stderr, "-p not supported for Mac NVRAM store.\n"); + return 1; + } +#endif + PrintOFVariables(); + break; + + case 'x' : + gUseXML = true; + break; + + case 'f': +#if TARGET_OS_BRIDGE + if (gBridgeToIntel) { + fprintf(stderr, "-f not supported for Mac NVRAM store.\n"); + return 1; + } +#endif + cnt++; + if (cnt < argc && *argv[cnt] != '-') { + ParseFile(argv[cnt]); + } else { + UsageMessage("missing filename"); + } + break; + + case 'd': + cnt++; + if (cnt < argc && *argv[cnt] != '-') { +#if TARGET_OS_BRIDGE + if (gBridgeToIntel) { + if ((result = DeleteMacOFVariable(argv[cnt])) != KERN_SUCCESS) { + errx(1, "Error deleting variable - '%s': %s (0x%08x)", argv[cnt], + mach_error_string(result), result); + } + } + else +#endif + { + DeleteOFVariable(argv[cnt]); + } + } else { + UsageMessage("missing name"); + } + break; + + case 'c': +#if TARGET_OS_BRIDGE + if (gBridgeToIntel) { + fprintf(stderr, "-c not supported for Mac NVRAM store.\n"); + return 1; + } +#endif + ClearOFVariables(); + break; + case 's': + // -s option is unadvertised -- advises the kernel more forcibly to + // commit the variable to nonvolatile storage + gUseForceSync = true; + break; +#if TARGET_OS_BRIDGE + case 'm': + // used to set nvram variables on the Intel side + // from the ARM side (Bridge -> Mac) + fprintf(stdout, "Using Mac NVRAM store.\n"); + + LinkMacNVRAMSymbols(); + gBridgeToIntel = true; + break; +#endif + + default: + strcpy(errorMessage, "no such option as --"); + errorMessage[strlen(errorMessage)-1] = *str; + UsageMessage(errorMessage); + } + } + } else { + // Other arguments will be firmware variable requests. + argcount++; + SetOrGetOFVariable(str); + } + } + + // radar:25206371 + if (argcount == 0 && gUseForceSync == true) { + NVRamSyncNow(""); + } + + IOObjectRelease(gOptionsRef); + + return 0; +} + +// UsageMessage(message) +// +// Print the usage information and exit. +// +static void UsageMessage(char *message) +{ + warnx("(usage: %s)", message); + + printf("%s [-x] [-p] [-f filename] [-d name] [-c] name[=value] ...\n", gToolName); + printf("\t-x use XML format for printing or reading variables\n"); + printf("\t (must appear before -p or -f)\n"); + printf("\t-p print all firmware variables\n"); + printf("\t-f set firmware variables from a text file\n"); + printf("\t-d delete the named variable\n"); + printf("\t-c delete all variables\n"); +#if TARGET_OS_BRIDGE + printf("\t-m set nvram variables on macOS from bridgeOS\n"); +#endif + printf("\tname=value set named variable\n"); + printf("\tname print variable\n"); + printf("Note that arguments and options are executed in order.\n"); + + exit(1); +} + + +// States for ParseFile. +enum { + kFirstColumn = 0, + kScanComment, + kFindName, + kCollectName, + kFindValue, + kCollectValue, + kContinueValue, + kSetenv, + + kMaxStringSize = 0x800, + kMaxNameSize = 0x100 +}; + + +// ParseFile(fileName) +// +// Open and parse the specified file. +// +static void ParseFile(char *fileName) +{ + long state, ni = 0, vi = 0; + int tc; + char name[kMaxNameSize]; + char value[kMaxStringSize]; + FILE *patches; + kern_return_t kret; + + if (gUseXML) { + ParseXMLFile(fileName); + return; + } + + patches = fopen(fileName, "r"); + if (patches == 0) { + err(1, "Couldn't open patch file - '%s'", fileName); + } + + state = kFirstColumn; + while ((tc = getc(patches)) != EOF) { + if(ni==(kMaxNameSize-1)) + errx(1, "Name exceeded max length of %d", kMaxNameSize); + if(vi==(kMaxStringSize-1)) + errx(1, "Value exceeded max length of %d", kMaxStringSize); + switch (state) { + case kFirstColumn : + ni = 0; + vi = 0; + if (tc == '#') { + state = kScanComment; + } else if (tc == '\n') { + // state stays kFirstColumn. + } else if (isspace(tc)) { + state = kFindName; + } else { + state = kCollectName; + name[ni++] = tc; + } + break; + + case kScanComment : + if (tc == '\n') { + state = kFirstColumn; + } else { + // state stays kScanComment. + } + break; + + case kFindName : + if (tc == '\n') { + state = kFirstColumn; + } else if (isspace(tc)) { + // state stays kFindName. + } else { + state = kCollectName; + name[ni++] = tc; + } + break; + + case kCollectName : + if (tc == '\n') { + name[ni] = 0; + warnx("Name must be followed by white space - '%s'", name); + state = kFirstColumn; + } else if (isspace(tc)) { + state = kFindValue; + } else { + name[ni++] = tc; + // state staus kCollectName. + } + break; + + case kFindValue : + case kContinueValue : + if (tc == '\n') { + state = kSetenv; + } else if (isspace(tc)) { + // state stays kFindValue or kContinueValue. + } else { + state = kCollectValue; + value[vi++] = tc; + } + break; + + case kCollectValue : + if (tc == '\n') { + if (value[vi-1] == '\\') { + value[vi-1] = '\r'; + state = kContinueValue; + } else { + state = kSetenv; + } + } else { + // state stays kCollectValue. + value[vi++] = tc; + } + break; + } + + if (state == kSetenv) { + name[ni] = 0; + value[vi] = 0; + if ((kret = SetOFVariable(name, value)) != KERN_SUCCESS) { + errx(1, "Error setting variable - '%s': %s", name, + mach_error_string(kret)); + } + state = kFirstColumn; + } + } + + if (state != kFirstColumn) { + errx(1, "Last line ended abruptly"); + } +} + +// ParseXMLFile(fileName) +// +// Open and parse the specified file in XML format, +// and set variables appropriately. +// +static void ParseXMLFile(char *fileName) +{ + CFPropertyListRef plist; + int fd; + struct stat sb; + char *buffer; + CFReadStreamRef stream; + CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0; + + fd = open(fileName, O_RDONLY | O_NOFOLLOW, S_IFREG); + if (fd == -1) { + errx(1, "Could not open %s: %s", fileName, strerror(errno)); + } + + if (fstat(fd, &sb) == -1) { + errx(1, "Could not fstat %s: %s", fileName, strerror(errno)); + } + + if (sb.st_size > UINT32_MAX) { + errx(1, "too big for our purposes"); + } + + buffer = malloc((size_t)sb.st_size); + if (buffer == NULL) { + errx(1, "Could not allocate buffer"); + } + + if (read(fd, buffer, (size_t)sb.st_size) != sb.st_size) { + errx(1, "Could not read %s: %s", fileName, strerror(errno)); + } + + close(fd); + + stream = CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault, + (const UInt8 *)buffer, + (CFIndex)sb.st_size, + kCFAllocatorNull); + if (stream == NULL) { + errx(1, "Could not create stream from serialized data"); + } + + if (!CFReadStreamOpen(stream)) { + errx(1, "Could not open the stream"); + } + + plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, + stream, + (CFIndex)sb.st_size, + kCFPropertyListImmutable, + &format, + NULL); + + if (plist == NULL) { + errx(1, "Error parsing XML file"); + } + + CFReadStreamClose(stream); + + CFRelease(stream); + + free(buffer); + + CFDictionaryApplyFunction(plist, &SetOFVariableFromFile, 0); + + CFRelease(plist); +} + +// SetOrGetOFVariable(str) +// +// Parse the input string, then set, append or get +// the specified firmware variable. +// +static void SetOrGetOFVariable(char *str) +{ + long set = 0; + long append = 0; + char *name; + char *value; + CFStringRef nameRef = NULL; + CFTypeRef valueRef = NULL; + CFMutableStringRef appended = NULL; + kern_return_t result; + + // OF variable name is first. + name = str; + + // Find the equal sign for set or += for append + while (*str) { + if (*str == '+' && *(str+1) == '=') { + append = 1; + *str++ = '\0'; + *str++ = '\0'; + break; + } + + if (*str == '=') { + set = 1; + *str++ = '\0'; + break; + } + str++; + } + + // Read the current value if appending or if no =/+= + if (append == 1 || (set == 0 && append == 0)) { +#if TARGET_OS_BRIDGE + if (gBridgeToIntel) { + result = GetMacOFVariable(name, &value); + if (result != KERN_SUCCESS) { + errx(1, "Error getting variable - '%s': %s", name, + mach_error_string(result)); + } + nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingUTF8); + valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value, kCFStringEncodingUTF8); + free(value); + } + else +#endif + { + result = GetOFVariable(name, &nameRef, &valueRef); + if (result != KERN_SUCCESS) { + errx(1, "Error getting variable - '%s': %s", name, + mach_error_string(result)); + } + } + } + + if (set == 1) { + // On sets, the OF variable's value follows the equal sign. + value = str; + } + + if (append == 1) { + // On append, the value to append follows the += substring + appended = CFStringCreateMutableCopy(NULL, 0, valueRef); + CFStringAppendCString(appended, str, kCFStringEncodingUTF8); + value = (char*)CFStringGetCStringPtr(appended, kCFStringEncodingUTF8); + } + + if (set == 1 || append == 1) { +#if TARGET_OS_BRIDGE + if (gBridgeToIntel) { + result = SetMacOFVariable(name, value); + } + else +#endif + { + result = SetOFVariable(name, value); + NVRamSyncNow(name); /* Try syncing the new data to device, best effort! */ + } + if (result != KERN_SUCCESS) { + errx(1, "Error setting variable - '%s': %s", name, + mach_error_string(result)); + } + } else { + PrintOFVariable(nameRef, valueRef, 0); + } + if ( nameRef ) CFRelease(nameRef); + if ( valueRef ) CFRelease(valueRef); + if ( appended ) CFRelease(appended); +} + +#if TARGET_OS_BRIDGE +static kern_return_t LinkMacNVRAMSymbols() +{ + gDL_handle = dlopen("libMacEFIHostInterface.dylib", RTLD_LAZY); + if (gDL_handle == NULL) { + errx(errno, "Failed to dlopen libMacEFIHostInterface.dylib"); + return KERN_FAILURE; /* NOTREACHED */ + } + + hostInterfaceInitialize_fptr = dlsym(gDL_handle, "hostInterfaceInitialize"); + if (hostInterfaceInitialize_fptr == NULL) { + errx(errno, "failed to link hostInterfaceInitialize"); + } + createNvramHostInterface_fptr = dlsym(gDL_handle, "createNvramHostInterface"); + if (createNvramHostInterface_fptr == NULL) { + errx(errno, "failed to link createNvramHostInterface"); + } + destroyNvramHostInterface_fptr = dlsym(gDL_handle, "destroyNvramHostInterface"); + if (destroyNvramHostInterface_fptr == NULL) { + errx(errno, "failed to link destroyNvramHostInterface"); + } + getNVRAMVariable_fptr = dlsym(gDL_handle, "getNVRAMVariable"); + if (getNVRAMVariable_fptr == NULL) { + errx(errno, "failed to link getNVRAMVariable"); + } + setNVRAMVariable_fptr = dlsym(gDL_handle, "setNVRAMVariable"); + if (setNVRAMVariable_fptr == NULL) { + errx(errno, "failed to link setNVRAMVariable"); + } + deleteNVRAMVariable_fptr = dlsym(gDL_handle, "deleteNVRAMVariable"); + if (deleteNVRAMVariable_fptr == NULL) { + errx(errno, "failed to link deleteNVRAMVariable"); + } + hostInterfaceDeinitialize_fptr = dlsym(gDL_handle, "hostInterfaceDeinitialize"); + if (hostInterfaceDeinitialize_fptr == NULL) { + errx(errno, "failed to link hostInterfaceDeinitialize"); + } + + /* also do the initialization */ + hostInterfaceInitialize_fptr(); + gNvramInterface = createNvramHostInterface_fptr(NULL); + + return KERN_SUCCESS; +} +#endif + +// GetOFVariable(name, nameRef, valueRef) +// +// Get the named firmware variable. +// Return it and it's symbol in valueRef and nameRef. +// +static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef, + CFTypeRef *valueRef) +{ + *nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name, + kCFStringEncodingUTF8); + if (*nameRef == 0) { + errx(1, "Error creating CFString for key %s", name); + } + + *valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, *nameRef, 0, 0); + if (*valueRef == 0) return kIOReturnNotFound; + + return KERN_SUCCESS; +} + +#if TARGET_OS_BRIDGE +// GetMacOFVariable(name, value) +// +// Get the named firmware variable from the Intel side. +// Return the value in value +// +static kern_return_t GetMacOFVariable(char *name, char **value) +{ + uint32_t value_size; + + return getNVRAMVariable_fptr(gNvramInterface, name, value, &value_size); +} +#endif + +// SetOFVariable(name, value) +// +// Set or create an firmware variable with name and value. +// +static kern_return_t SetOFVariable(char *name, char *value) +{ + CFStringRef nameRef; + CFTypeRef valueRef; + CFTypeID typeID; + kern_return_t result = KERN_SUCCESS; + + nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name, + kCFStringEncodingUTF8); + if (nameRef == 0) { + errx(1, "Error creating CFString for key %s", name); + } + + valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, nameRef, 0, 0); + if (valueRef) { + typeID = CFGetTypeID(valueRef); + CFRelease(valueRef); + + valueRef = ConvertValueToCFTypeRef(typeID, value); + if (valueRef == 0) { + errx(1, "Error creating CFTypeRef for value %s", value); + } result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef); + } else { + while (1) { + // In the default case, try data, string, number, then boolean. + + valueRef = ConvertValueToCFTypeRef(CFDataGetTypeID(), value); + if (valueRef != 0) { + result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef); + if (result == KERN_SUCCESS) break; + } + + valueRef = ConvertValueToCFTypeRef(CFStringGetTypeID(), value); + if (valueRef != 0) { + result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef); + if (result == KERN_SUCCESS) break; + } + + valueRef = ConvertValueToCFTypeRef(CFNumberGetTypeID(), value); + if (valueRef != 0) { + result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef); + if (result == KERN_SUCCESS) break; + } + + valueRef = ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value); + if (valueRef != 0) { + result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef); + if (result == KERN_SUCCESS) break; + } + + break; + } + } + + CFRelease(nameRef); + + return result; +} + +#if TARGET_OS_BRIDGE +static kern_return_t SetMacOFVariable(char *name, char *value) +{ + return setNVRAMVariable_fptr(gNvramInterface, name, value); +} +#endif + +// DeleteOFVariable(name) +// +// Delete the named firmware variable. +// +// +static void DeleteOFVariable(char *name) +{ + SetOFVariable(kIONVRAMDeletePropertyKey, name); +} + +#if TARGET_OS_BRIDGE +static kern_return_t DeleteMacOFVariable(char *name) +{ + return deleteNVRAMVariable_fptr(gNvramInterface, name); +} +#endif + +static void NVRamSyncNow(char *name) +{ + if (!gUseForceSync) { + SetOFVariable(kIONVRAMSyncNowPropertyKey, name); + } else { + SetOFVariable(kIONVRAMForceSyncNowPropertyKey, name); + } +} + +// PrintOFVariables() +// +// Print all of the firmware variables. +// +static void PrintOFVariables(void) +{ + kern_return_t result; + CFMutableDictionaryRef dict; + + result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0); + if (result != KERN_SUCCESS) { + errx(1, "Error getting the firmware variables: %s", mach_error_string(result)); + } + + if (gUseXML) { + CFDataRef data; + + data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL ); + if (data == NULL) { + errx(1, "Error converting variables to xml"); + } + + fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout); + + CFRelease(data); + + } else { + + CFDictionaryApplyFunction(dict, &PrintOFVariable, 0); + + } + + CFRelease(dict); +} + +// PrintOFVariable(key, value, context) +// +// Print the given firmware variable. +// +static void PrintOFVariable(const void *key, const void *value, void *context) +{ + long cnt, cnt2; + CFIndex nameLen; + char *nameBuffer = 0; + const char *nameString; + char numberBuffer[10]; + const uint8_t *dataPtr; + uint8_t dataChar; + char *dataBuffer = 0; + CFIndex valueLen; + char *valueBuffer = 0; + const char *valueString = 0; + uint32_t number; + long length; + CFTypeID typeID; + + if (gUseXML) { + CFDataRef data; + CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, &key, &value, 1, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (dict == NULL) { + errx(1, "Error creating dictionary for variable value"); + } + + data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL ); + if (data == NULL) { + errx(1, "Error creating xml plist for variable"); + } + + fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout); + + CFRelease(dict); + CFRelease(data); + return; + } + + // Get the OF variable's name. + nameLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key), + kCFStringEncodingUTF8) + 1; + nameBuffer = malloc(nameLen); + if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) ) + nameString = nameBuffer; + else { + warnx("Unable to convert property name to C string"); + nameString = ""; + } + + // Get the OF variable's type. + typeID = CFGetTypeID(value); + + if (typeID == CFBooleanGetTypeID()) { + if (CFBooleanGetValue(value)) valueString = "true"; + else valueString = "false"; + } else if (typeID == CFNumberGetTypeID()) { + CFNumberGetValue(value, kCFNumberSInt32Type, &number); + if (number == 0xFFFFFFFF) sprintf(numberBuffer, "-1"); + else if (number < 1000) sprintf(numberBuffer, "%d", number); + else sprintf(numberBuffer, "0x%x", number); + valueString = numberBuffer; + } else if (typeID == CFStringGetTypeID()) { + valueLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), + kCFStringEncodingUTF8) + 1; + valueBuffer = malloc(valueLen + 1); + if ( valueBuffer && CFStringGetCString(value, valueBuffer, valueLen, kCFStringEncodingUTF8) ) + valueString = valueBuffer; + else { + warnx("Unable to convert value to C string"); + valueString = ""; + } + } else if (typeID == CFDataGetTypeID()) { + length = CFDataGetLength(value); + if (length == 0) valueString = ""; + else { + dataBuffer = malloc(length * 3 + 1); + if (dataBuffer != 0) { + dataPtr = CFDataGetBytePtr(value); + for (cnt = cnt2 = 0; cnt < length; cnt++) { + dataChar = dataPtr[cnt]; + if (isprint(dataChar) && dataChar != '%') { + dataBuffer[cnt2++] = dataChar; + } else { + sprintf(dataBuffer + cnt2, "%%%02x", dataChar); + cnt2 += 3; + } + } + dataBuffer[cnt2] = '\0'; + valueString = dataBuffer; + } + } + } else { + valueString=""; + } + + if ((nameString != 0) && (valueString != 0)) + printf("%s\t%s\n", nameString, valueString); + + if (dataBuffer != 0) free(dataBuffer); + if (nameBuffer != 0) free(nameBuffer); + if (valueBuffer != 0) free(valueBuffer); +} + +// ClearOFVariables() +// +// Deletes all OF variables +// +static void ClearOFVariables(void) +{ + kern_return_t result; + CFMutableDictionaryRef dict; + + result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0); + if (result != KERN_SUCCESS) { + errx(1, "Error getting the firmware variables: %s", mach_error_string(result)); + } + CFDictionaryApplyFunction(dict, &ClearOFVariable, 0); + + CFRelease(dict); +} + +static void ClearOFVariable(const void *key, const void *value, void *context) +{ + kern_return_t result; + result = IORegistryEntrySetCFProperty(gOptionsRef, + CFSTR(kIONVRAMDeletePropertyKey), key); + if (result != KERN_SUCCESS) { + assert(CFGetTypeID(key) == CFStringGetTypeID()); + const char *keyStr = CFStringGetCStringPtr(key, kCFStringEncodingUTF8); + char *keyBuffer = NULL; + size_t keyBufferLen = 0; + if (!keyStr) { + keyBufferLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key), kCFStringEncodingUTF8) + 1; + keyBuffer = (char *)malloc(keyBufferLen); + if (keyBuffer != NULL && CFStringGetCString(key, keyBuffer, keyBufferLen, kCFStringEncodingUTF8)) { + keyStr = keyBuffer; + } else { + warnx("Unable to convert property name to C string"); + keyStr = ""; + } + } + + warnx("Error clearing firmware variable %s: %s", keyStr, mach_error_string(result)); + if (keyBuffer) { + free(keyBuffer); + } + } +} + +// ConvertValueToCFTypeRef(typeID, value) +// +// Convert the value into a CFType given the typeID. +// +static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value) +{ + CFTypeRef valueRef = 0; + long cnt, cnt2, length; + unsigned long number, tmp; + + if (typeID == CFBooleanGetTypeID()) { + if (!strcmp("true", value)) valueRef = kCFBooleanTrue; + else if (!strcmp("false", value)) valueRef = kCFBooleanFalse; + } else if (typeID == CFNumberGetTypeID()) { + number = strtol(value, 0, 0); + valueRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, + &number); + } else if (typeID == CFStringGetTypeID()) { + valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value, + kCFStringEncodingUTF8); + } else if (typeID == CFDataGetTypeID()) { + length = strlen(value); + for (cnt = cnt2 = 0; cnt < length; cnt++, cnt2++) { + if (value[cnt] == '%') { + if (!ishexnumber(value[cnt + 1]) || + !ishexnumber(value[cnt + 2])) return 0; + number = toupper(value[++cnt]) - '0'; + if (number > 9) number -= 7; + tmp = toupper(value[++cnt]) - '0'; + if (tmp > 9) tmp -= 7; + number = (number << 4) + tmp; + value[cnt2] = number; + } else value[cnt2] = value[cnt]; + } + valueRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)value, + cnt2, kCFAllocatorDefault); + } else return 0; + + return valueRef; +} + +static void SetOFVariableFromFile(const void *key, const void *value, void *context) +{ + kern_return_t result; + + result = IORegistryEntrySetCFProperty(gOptionsRef, key, value); + if ( result != KERN_SUCCESS ) { + long nameLen; + char *nameBuffer; + char *nameString; + + // Get the variable's name. + nameLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key), + kCFStringEncodingUTF8) + 1; + nameBuffer = malloc(nameLen); + if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) ) + nameString = nameBuffer; + else { + warnx("Unable to convert property name to C string"); + nameString = ""; + } + errx(1, "Error setting variable - '%s': %s", nameString, + mach_error_string(result)); + } +} -- cgit v1.2.3-56-ge451