]> git.saurik.com Git - apple/system_cmds.git/blobdiff - nvram.tproj/nvram.c
system_cmds-880.100.5.tar.gz
[apple/system_cmds.git] / nvram.tproj / nvram.c
index d97fb9d97e3e100f0d9aac9f46978fc73ea3242e..b10ab2eeed62a43c964036b31297842208885b6a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -26,26 +26,59 @@ cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall
 #include <stdio.h>
 #include <IOKit/IOKitLib.h>
 #include <IOKit/IOKitKeys.h>
+#include <IOKit/IOKitKeysPrivate.h>
 #include <CoreFoundation/CoreFoundation.h>
+#include <err.h>
+#include <mach/mach_error.h>
+#include <sys/stat.h>
 
 // Prototypes
-static void Error(char *format, long item);
-static void FatalError(long exitValue, char *format, long item);
-static void UsageMessage(char *message);
-static void ParseFile(char *fileName);
+static void UsageMessage(const char *message);
+static void ParseFile(const char *fileName);
+static void ParseXMLFile(const 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 kern_return_t GetOFVariable(const char *name, CFStringRef *nameRef,
+                                   CFTypeRef *valueRef);
+static kern_return_t SetOFVariable(const char *name, const char *value);
+static void DeleteOFVariable(const char *name);
 static void PrintOFVariables(void);
 static void PrintOFVariable(const void *key,const void *value,void *context);
-static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value);
+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, const char *value);
+
+static void NVRamSyncNow(void);
 
 // Global Variables
-static char                *gToolName;
 static io_registry_entry_t gOptionsRef;
+static io_registry_entry_t gSystemOptionsRef;
+static io_registry_entry_t gSelectedOptionsRef;
+static bool                gUseXML;
+static bool                gUseForceSync;
+
+#if TARGET_OS_BRIDGE /* Stuff for nvram bridge -> intel */
+#include <dlfcn.h>
+#include <libMacEFIManager/MacEFIHostInterfaceAPI.h>
+
+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)
 {
@@ -53,112 +86,163 @@ int main(int argc, char **argv)
   char                *str, errorMessage[256];
   kern_return_t       result;
   mach_port_t         masterPort;
-  
-  // Get the name of the command.
-  gToolName = strrchr(argv[0], '/');
-  if (gToolName != 0) gToolName++;
-  else gToolName = argv[0];
-  
+  int                 argcount = 0;
+
   result = IOMasterPort(bootstrap_port, &masterPort);
   if (result != KERN_SUCCESS) {
-    FatalError(-1, "Error (%d) getting the IOMaster port", result);
-    exit(-1);
+    errx(1, "Error getting the IOMaster port: %s",
+        mach_error_string(result));
   }
-  
+
   gOptionsRef = IORegistryEntryFromPath(masterPort, "IODeviceTree:/options");
   if (gOptionsRef == 0) {
-    FatalError(-1, "nvram is not supported on this system.", -1);
-    exit(-1);
+    errx(1, "nvram is not supported on this system");
   }
-  
+
+  gSystemOptionsRef = IORegistryEntryFromPath(masterPort, "IOService:/options/options-system");
+
+  gSelectedOptionsRef = gOptionsRef;
+
   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' :
-         PrintOFVariables();
-         break;
-         
-       case 'f':
-         cnt++;
-         if (cnt < argc && *argv[cnt] != '-') {
-           ParseFile(argv[cnt]);
-         } else {
-           UsageMessage("missing filename");
-         }
-         break;
-         
-       case 'd':
-         cnt++;
-         if (cnt < argc && *argv[cnt] != '-') {
-           DeleteOFVariable(argv[cnt]);
-         } else {
-           UsageMessage("missing name");
-         }
-         break;
-         
-       default:
-         strcpy(errorMessage, "no such option as --");
-         errorMessage[strlen(errorMessage)-1] = *str;
-         UsageMessage(errorMessage);
-       }
+        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
+
+          case 'z':
+            // -z option is unadvertised -- attempts to use the options-system node
+            // to write to the system NVRAM region if available
+            if (gSystemOptionsRef) {
+              fprintf(stderr, "Selecting options-system node.\n");
+              gSelectedOptionsRef = gSystemOptionsRef;
+            } else {
+              fprintf(stderr, "No options-system node, using options.\n");
+            }
+            break;
+
+          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);
       }
-    } else {
-      // Other arguments will be firmware variable requests.
-      SetOrGetOFVariable(str);
-    }
   }
-  
-  IOObjectRelease(gOptionsRef);
-  
-  return 0;
-}
 
+  // radar:25206371
+  if (argcount == 0 && gUseForceSync == true) {
+    NVRamSyncNow();
+  }
 
-// Error(format, item)
-//
-//   Print a message on standard error.
-//
-static void Error(char *format, long item)
-{
-  fprintf(stderr, "%s: ", gToolName);
-  fprintf(stderr, format, item);
-  fprintf(stderr, "\n");
-}
+  IOObjectRelease(gOptionsRef);
 
+  if (gSystemOptionsRef) {
+    IOObjectRelease(gSystemOptionsRef);
+  }
 
-// FatalError(exitValue, format, item)
-//
-//   Print a message on standard error and exit with value.
-//
-static void FatalError(long exitValue, char *format, long item)
-{
-  fprintf(stderr, "%s: ", gToolName);
-  fprintf(stderr, format, item);
-  fprintf(stderr, "\n");
-  
-  exit(exitValue);
+  return 0;
 }
 
-
 // UsageMessage(message)
 //
 //   Print the usage information and exit.
 //
-static void UsageMessage(char *message)
+static void UsageMessage(const char *message)
 {
-  Error("(usage: %s)", (long)message);
-  
-  printf("%s [-p] [-f filename] [-d name] name[=value] ...\n", gToolName);
+  warnx("(usage: %s)", message);
+
+  printf("nvram [-x] [-p] [-f filename] [-d name] [-c] name[=value] ...\n");
+  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);
 }
 
@@ -173,7 +257,7 @@ enum {
   kCollectValue,
   kContinueValue,
   kSetenv,
-  
+
   kMaxStringSize = 0x800,
   kMaxNameSize = 0x100
 };
@@ -183,130 +267,222 @@ enum {
 //
 //   Open and parse the specified file.
 //
-static void ParseFile(char *fileName)
+static void ParseFile(const char *fileName)
 {
-  long state, tc, ni = 0, vi = 0;
+  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) {
-    FatalError(errno, "Couldn't open patch file - '%s'", (long)fileName);
+    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;
+        state = kScanComment;
       } else if (tc == '\n') {
-       // state stays kFirstColumn.
+        // state stays kFirstColumn.
       } else if (isspace(tc)) {
-       state = kFindName;
+        state = kFindName;
       } else {
-       state = kCollectName;
-       name[ni++] = tc;
+        state = kCollectName;
+        name[ni++] = tc;
       }
       break;
-      
+
     case kScanComment :
       if (tc == '\n') {
-       state = kFirstColumn;
+        state = kFirstColumn;
       } else {
-       // state stays kScanComment.
+        // state stays kScanComment.
       }
       break;
-      
+
     case kFindName :
       if (tc == '\n') {
-       state = kFirstColumn;
+        state = kFirstColumn;
       } else if (isspace(tc)) {
-       // state stays kFindName.
+        // state stays kFindName.
       } else {
-       state = kCollectName;
-       name[ni++] = tc;
+        state = kCollectName;
+        name[ni++] = tc;
       }
       break;
-      
+
     case kCollectName :
       if (tc == '\n') {
-       name[ni] = 0;
-       Error("Name must be followed by white space - '%s'", (long)name);
-       state = kFirstColumn;
+        name[ni] = 0;
+        warnx("Name must be followed by white space - '%s'", name);
+        state = kFirstColumn;
       } else if (isspace(tc)) {
-       state = kFindValue;
+        state = kFindValue;
       } else {
-       name[ni++] = tc;
-       // state staus kCollectName.
+        name[ni++] = tc;
+        // state staus kCollectName.
       }
       break;
-      
+
     case kFindValue :
     case kContinueValue :
       if (tc == '\n') {
-       state = kSetenv;
+        state = kSetenv;
       } else if (isspace(tc)) {
-       // state stays kFindValue or kContinueValue.
+        // state stays kFindValue or kContinueValue.
       } else {
-       state = kCollectValue;
-       value[vi++] = tc;
+        state = kCollectValue;
+        value[vi++] = tc;
       }
       break;
-      
+
     case kCollectValue :
       if (tc == '\n') {
-       if (value[vi-1] == '\\') {
-         value[vi-1] = '\r';
-         state = kContinueValue;
-       } else {
-         state = kSetenv;
-       }
+        if (value[vi-1] == '\\') {
+          value[vi-1] = '\r';
+          state = kContinueValue;
+        } else {
+          state = kSetenv;
+        }
       } else {
-       // state stays kCollectValue.
-       value[vi++] = tc;
+        // state stays kCollectValue.
+        value[vi++] = tc;
       }
       break;
     }
-    
+
     if (state == kSetenv) {
       name[ni] = 0;
       value[vi] = 0;
-      if (SetOFVariable(name, value) != KERN_SUCCESS) {
-       FatalError(-1, "Error (-1) setting variable - '%s'", (long)name);
+      if ((kret = SetOFVariable(name, value)) != KERN_SUCCESS) {
+        errx(1, "Error setting variable - '%s': %s", name,
+             mach_error_string(kret));
       }
       state = kFirstColumn;
     }
   }
-  
+
   if (state != kFirstColumn) {
-    FatalError(-1, "Last line ended abruptly", 0);
+    errx(1, "Last line ended abruptly");
   }
 }
 
+// ParseXMLFile(fileName)
+//
+//   Open and parse the specified file in XML format,
+//   and set variables appropriately.
+//
+static void ParseXMLFile(const 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 or get the specified
-//   firmware variable.
+//   Parse the input string, then set, append or get
+//   the specified firmware variable.
 //
 static void SetOrGetOFVariable(char *str)
 {
-  long          set = 0;
-  char          *name;
-  char          *value;
-  CFStringRef   nameRef;
-  CFTypeRef     valueRef;
-  kern_return_t result;
-  
+  long               set = 0;
+  long               append = 0;
+  const 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
+
+  // 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';
@@ -314,144 +490,277 @@ static void SetOrGetOFVariable(char *str)
     }
     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;
-    
-    result = SetOFVariable(name, value);
-    if (result != KERN_SUCCESS) {
-      FatalError(-1, "Error (-1) setting variable - '%s'", (long)name);
+  }
+
+  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);
+      /* Try syncing the new data to device, best effort! */
+      NVRamSyncNow();
     }
-  } else {
-    result = GetOFVariable(name, &nameRef, &valueRef);
     if (result != KERN_SUCCESS) {
-      FatalError(-1, "Error (-1) getting variable - '%s'", (long)name);
+      errx(1, "Error setting variable - '%s': %s", name,
+           mach_error_string(result));
     }
-    
+  } else {
     PrintOFVariable(nameRef, valueRef, 0);
-    CFRelease(nameRef);
-    CFRelease(valueRef);
   }
+  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)
+static kern_return_t GetOFVariable(const char *name, CFStringRef *nameRef,
+                                   CFTypeRef *valueRef)
 {
   *nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
-                                      kCFStringEncodingUTF8);
+                                       kCFStringEncodingUTF8);
   if (*nameRef == 0) {
-    FatalError(-1, "Error (-1) creating CFString for key %s", (long)name);
+    errx(1, "Error creating CFString for key %s", name);
   }
-  
-  *valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, *nameRef, 0, 0);
-  if (*valueRef == 0) return -1;
-  
+
+  *valueRef = IORegistryEntryCreateCFProperty(gSelectedOptionsRef, *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)
+static kern_return_t SetOFVariable(const char *name, const char *value)
 {
   CFStringRef   nameRef;
   CFTypeRef     valueRef;
   CFTypeID      typeID;
-  kern_return_t result;
-  
+  kern_return_t result = KERN_SUCCESS;
+
   nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
-                                     kCFStringEncodingUTF8);
+                                      kCFStringEncodingUTF8);
   if (nameRef == 0) {
-    FatalError(-1, "Error (-1) creating CFString for key %s", (long)name);
+      errx(1, "Error creating CFString for key %s", name);
   }
-  
-  valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, nameRef, 0, 0);
+
+  valueRef = IORegistryEntryCreateCFProperty(gSelectedOptionsRef, nameRef, 0, 0);
   if (valueRef) {
-    typeID = CFGetTypeID(valueRef);
-    CFRelease(valueRef);
-    
-    valueRef = ConvertValueToCFTypeRef(typeID, value);
-    if (valueRef == 0) {
-      FatalError(-1, "Error (-1) creating CFTypeRef for value %s",(long)value);
-    }  result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
+      typeID = CFGetTypeID(valueRef);
+      CFRelease(valueRef);
+
+      valueRef = ConvertValueToCFTypeRef(typeID, value);
+      if (valueRef == 0) {
+          errx(1, "Error creating CFTypeRef for value %s", value);
+      }  result = IORegistryEntrySetCFProperty(gSelectedOptionsRef, 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;
+      while (1) {
+          // In the default case, try data, string, number, then boolean.
+
+          valueRef = ConvertValueToCFTypeRef(CFDataGetTypeID(), value);
+          if (valueRef != 0) {
+              result = IORegistryEntrySetCFProperty(gSelectedOptionsRef, nameRef, valueRef);
+              if (result == KERN_SUCCESS) break;
+          }
+
+          valueRef = ConvertValueToCFTypeRef(CFStringGetTypeID(), value);
+          if (valueRef != 0) {
+              result = IORegistryEntrySetCFProperty(gSelectedOptionsRef, nameRef, valueRef);
+              if (result == KERN_SUCCESS) break;
+          }
+
+          valueRef = ConvertValueToCFTypeRef(CFNumberGetTypeID(), value);
+          if (valueRef != 0) {
+              result = IORegistryEntrySetCFProperty(gSelectedOptionsRef, nameRef, valueRef);
+              if (result == KERN_SUCCESS) break;
+          }
+
+          valueRef = ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value);
+          if (valueRef != 0) {
+              result = IORegistryEntrySetCFProperty(gSelectedOptionsRef, nameRef, valueRef);
+              if (result == KERN_SUCCESS) break;
+          }
+
+          break;
       }
-      
-      result = -1;
-      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)
+static void DeleteOFVariable(const 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(void)
+{
+  if (!gUseForceSync) {
+    SetOFVariable(kIONVRAMSyncNowPropertyKey, kIONVRAMSyncNowPropertyKey);
+  } else {
+    SetOFVariable(kIONVRAMForceSyncNowPropertyKey, kIONVRAMForceSyncNowPropertyKey);
+  }
+}
 
 // PrintOFVariables()
 //
 //   Print all of the firmware variables.
 //
-static void PrintOFVariables()
+static void PrintOFVariables(void)
 {
   kern_return_t          result;
   CFMutableDictionaryRef dict;
-  
-  result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
+
+  result = IORegistryEntryCreateCFProperties(gSelectedOptionsRef, &dict, 0, 0);
   if (result != KERN_SUCCESS) {
-    FatalError(-1, "Error (%d) getting the firmware variables", result);
+    errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
   }
-  CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
-  
+
+  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.
@@ -469,22 +778,44 @@ static void PrintOFVariable(const void *key, const void *value, void *context)
   CFIndex       valueLen;
   char          *valueBuffer = 0;
   const char    *valueString = 0;
-  uint32_t      number, length;
+  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 = CFStringGetLength(key) + 1;
+  nameLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key),
+      kCFStringEncodingUTF8) + 1;
   nameBuffer = malloc(nameLen);
   if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
     nameString = nameBuffer;
   else {
-    Error("Error (-1) Unable to convert property name to C string", 0);
+    warnx("Unable to convert property name to C string");
     nameString = "<UNPRINTABLE>";
   }
-  
+
   // Get the OF variable's type.
   typeID = CFGetTypeID(value);
-  
+
   if (typeID == CFBooleanGetTypeID()) {
     if (CFBooleanGetValue(value)) valueString = "true";
     else valueString = "false";
@@ -495,12 +826,13 @@ static void PrintOFVariable(const void *key, const void *value, void *context)
     else sprintf(numberBuffer, "0x%x", number);
     valueString = numberBuffer;
   } else if (typeID == CFStringGetTypeID()) {
-    valueLen = CFStringGetLength(value) + 1;
+    valueLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value),
+        kCFStringEncodingUTF8) + 1;
     valueBuffer = malloc(valueLen + 1);
     if ( valueBuffer && CFStringGetCString(value, valueBuffer, valueLen, kCFStringEncodingUTF8) )
       valueString = valueBuffer;
     else {
-      Error("Error (-1) Unable to convert value to C string", 0);
+      warnx("Unable to convert value to C string");
       valueString = "<UNPRINTABLE>";
     }
   } else if (typeID == CFDataGetTypeID()) {
@@ -509,70 +841,142 @@ static void PrintOFVariable(const void *key, const void *value, void *context)
     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)) dataBuffer[cnt2++] = dataChar;
-         else {
-           sprintf(dataBuffer + cnt2, "%%%02x", dataChar);
-           cnt2 += 3;
-         }
-       }
-       dataBuffer[cnt2] = '\0';
-       valueString = dataBuffer;
+        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="<INVALID>";
   }
-  
+
   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(gSelectedOptionsRef, &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(gSelectedOptionsRef,
+                                        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 = "<UNPRINTABLE>";
+      }
+    }
+
+    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)
+static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, const 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, value,
-                                          cnt2, kCFAllocatorDefault);
-  } else return 0;
-  
-  return valueRef;
+    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);
+      char valueCopy[length + 1];
+
+      for (cnt = cnt2 = 0; cnt < length; cnt++, cnt2++) {
+        if (value[cnt] == '%') {
+          if ((cnt + 2 > length) ||
+              !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;
+          valueCopy[cnt2] = number;
+        } else valueCopy[cnt2] = value[cnt];
+      }
+      valueRef = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)valueCopy, cnt2);
+    } else return 0;
+
+    return valueRef;
 }
 
+static void SetOFVariableFromFile(const void *key, const void *value, void *context)
+{
+  kern_return_t result;
+
+  result = IORegistryEntrySetCFProperty(gSelectedOptionsRef, 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 = "<UNPRINTABLE>";
+    }
+    errx(1, "Error setting variable - '%s': %s", nameString,
+         mach_error_string(result));
+  }
+}