]> git.saurik.com Git - apple/system_cmds.git/blobdiff - nvram.tproj/nvram.c
system_cmds-597.1.1.tar.gz
[apple/system_cmds.git] / nvram.tproj / nvram.c
index 9fbbe4d45f06b389550f9d3db1ca1f6243c43503..4fef3a11f2e9d03413997adeccfdee4df56bc028 100644 (file)
@@ -1,25 +1,22 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2012 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *
+ * 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
+ * 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@
  */
 /*
@@ -30,12 +27,13 @@ cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall
 #include <IOKit/IOKitLib.h>
 #include <IOKit/IOKitKeys.h>
 #include <CoreFoundation/CoreFoundation.h>
+#include <err.h>
+#include <mach/mach_error.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 ParseXMLFile(char *fileName);
 static void SetOrGetOFVariable(char *str);
 static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
                                   CFTypeRef *valueRef);
@@ -43,11 +41,17 @@ 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;
 
 
 int main(int argc, char **argv)
@@ -64,14 +68,13 @@ int main(int argc, char **argv)
   
   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, "Error (%d) getting a reference to /options", -1);
-    exit(-1);
+    errx(1, "nvram is not supported on this system");
   }
   
   for (cnt = 1; cnt < argc; cnt++) {
@@ -83,7 +86,11 @@ int main(int argc, char **argv)
        case 'p' :
          PrintOFVariables();
          break;
-         
+
+       case 'x' :
+          gUseXML = true;
+          break;
+
        case 'f':
          cnt++;
          if (cnt < argc && *argv[cnt] != '-') {
@@ -102,6 +109,10 @@ int main(int argc, char **argv)
          }
          break;
          
+       case 'c':
+         ClearOFVariables();
+         break;
+         
        default:
          strcpy(errorMessage, "no such option as --");
          errorMessage[strlen(errorMessage)-1] = *str;
@@ -109,7 +120,7 @@ int main(int argc, char **argv)
        }
       }
     } else {
-      // Other arguments will be Open Firmware variable requests.
+      // Other arguments will be firmware variable requests.
       SetOrGetOFVariable(str);
     }
   }
@@ -119,45 +130,21 @@ int main(int argc, char **argv)
   return 0;
 }
 
-
-// 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");
-}
-
-
-// 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);
-}
-
-
 // UsageMessage(message)
 //
 //   Print the usage information and exit.
 //
 static void UsageMessage(char *message)
 {
-  Error("(usage: %s)", (long)message);
+  warnx("(usage: %s)", message);
   
-  printf("%s [-p] [-f filename] [-d name] name[=value] ...\n", gToolName);
-  printf("\t-p         print all Open Firmware variables\n");
-  printf("\t-f         set Open Firmware variables from a text file\n");
+  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");
   printf("\tname=value set named variable\n");
   printf("\tname       print variable\n");
   printf("Note that arguments and options are executed in order.\n");
@@ -192,14 +179,24 @@ static void ParseFile(char *fileName)
   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;
@@ -238,7 +235,7 @@ static void ParseFile(char *fileName)
     case kCollectName :
       if (tc == '\n') {
        name[ni] = 0;
-       Error("Name must be followed by white space - '%s'", (long)name);
+       warnx("Name must be followed by white space - '%s'", name);
        state = kFirstColumn;
       } else if (isspace(tc)) {
        state = kFindValue;
@@ -278,23 +275,87 @@ static void ParseFile(char *fileName)
     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(char *fileName)
+{
+        CFPropertyListRef plist;
+        CFURLRef fileURL = NULL;
+        CFStringRef filePath = NULL;
+        CFStringRef errorString = NULL;
+        CFDataRef data = NULL;
+        SInt32 errorCode = 0;
+
+        filePath = CFStringCreateWithCString(kCFAllocatorDefault, fileName, kCFStringEncodingUTF8);
+        if (filePath == NULL) {
+          errx(1, "Could not create file path string");
+        }
+
+        // Create a URL that specifies the file we will create to 
+        // hold the XML data.
+        fileURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault,    
+                                                 filePath,
+                                                 kCFURLPOSIXPathStyle,
+                                                 false /* not a directory */ );
+        if (fileURL == NULL) {
+          errx(1, "Could not create file path URL");
+        }
+
+        CFRelease(filePath);
+
+        if (! CFURLCreateDataAndPropertiesFromResource(
+                    kCFAllocatorDefault,
+                    fileURL,
+                    &data,
+                    NULL,      
+                    NULL,
+                    &errorCode) || data == NULL ) {
+          errx(1, "Error reading XML file (%d)", (int)errorCode);
+        }
+
+        CFRelease(fileURL);
+
+        plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
+                                                data,
+                                                kCFPropertyListImmutable,
+                                                &errorString);
+
+        CFRelease(data);
+
+        if (plist == NULL) {
+          errx(1, "Error parsing XML file");
+        }
+
+        if (errorString != NULL) {
+          errx(1, "Error parsing XML file: %s", CFStringGetCStringPtr(errorString, kCFStringEncodingUTF8));
+        }
+
+        CFDictionaryApplyFunction(plist, &SetOFVariableFromFile, 0);
+
+        CFRelease(plist);
+}
+
 // SetOrGetOFVariable(str)
 //
-//   Parse the input string the set or get the specified
-//   Open Firmware variable.
+//   Parse the input string, then set or get the specified
+//   firmware variable.
 //
 static void SetOrGetOFVariable(char *str)
 {
@@ -323,13 +384,16 @@ static void SetOrGetOFVariable(char *str)
     value = str;
     
     result = SetOFVariable(name, value);
+       NVRamSyncNow(name);                     /* Try syncing the new data to device, best effort! */
     if (result != KERN_SUCCESS) {
-      FatalError(-1, "Error (-1) setting variable - '%s'", (long)name);
+      errx(1, "Error setting variable - '%s': %s", name,
+           mach_error_string(result));
     }
   } else {
     result = GetOFVariable(name, &nameRef, &valueRef);
     if (result != KERN_SUCCESS) {
-      FatalError(-1, "Error (-1) getting variable - '%s'", (long)name);
+      errx(1, "Error getting variable - '%s': %s", name,
+           mach_error_string(result));
     }
     
     PrintOFVariable(nameRef, valueRef, 0);
@@ -341,20 +405,20 @@ static void SetOrGetOFVariable(char *str)
 
 // GetOFVariable(name, nameRef, valueRef)
 //
-//   Get the named Open Firmware variable.
+//   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,
-                                      kCFStringEncodingMacRoman);
+                                      kCFStringEncodingUTF8);
   if (*nameRef == 0) {
-    FatalError(-1, "Error 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;
+  if (*valueRef == 0) return kIOReturnNotFound;
   
   return KERN_SUCCESS;
 }
@@ -362,19 +426,19 @@ static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
 
 // SetOFVariable(name, value)
 //
-//   Set or create an Open Firmware variable with name and 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_return_t result = KERN_SUCCESS;
   
   nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
-                                     kCFStringEncodingMacRoman);
+                                     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);
@@ -384,7 +448,7 @@ static kern_return_t SetOFVariable(char *name, char *value)
     
     valueRef = ConvertValueToCFTypeRef(typeID, value);
     if (valueRef == 0) {
-      FatalError(-1, "Error (-1) creating CFTypeRef for value %s",(long)value);
+      errx(1, "Error creating CFTypeRef for value %s", value);
     }  result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
   } else {
     while (1) {
@@ -414,7 +478,6 @@ static kern_return_t SetOFVariable(char *name, char *value)
        if (result == KERN_SUCCESS) break;
       }
       
-      result = -1;
       break;
     }
   }
@@ -427,7 +490,7 @@ static kern_return_t SetOFVariable(char *name, char *value)
 
 // DeleteOFVariable(name)
 //
-//   Delete the named Open Firmware variable.
+//   Delete the named firmware variable.
 //   
 //
 static void DeleteOFVariable(char *name)
@@ -435,10 +498,14 @@ static void DeleteOFVariable(char *name)
   SetOFVariable(kIONVRAMDeletePropertyKey, name);
 }
 
+static void NVRamSyncNow(char *name)
+{
+  SetOFVariable(kIONVRAMSyncNowPropertyKey, name);
+}
 
 // PrintOFVariables()
 //
-//   Print all of the Open Firmware variables.
+//   Print all of the firmware variables.
 //
 static void PrintOFVariables()
 {
@@ -447,37 +514,64 @@ static void PrintOFVariables()
   
   result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
   if (result != KERN_SUCCESS) {
-    FatalError(-1, "Error (%d) getting the Open Firmware variables", result);
+    errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
+  }
+
+  if (gUseXML) {
+    CFDataRef data;
+
+    data = CFPropertyListCreateXMLData( kCFAllocatorDefault, dict );
+    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);
+
   }
-  CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
   
   CFRelease(dict);
 }
 
-
 // PrintOFVariable(key, value, context)
 //
-//   Print the given Open Firmware variable.
+//   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, length;
   CFTypeID      typeID;
   
   // Get the OF variable's name.
-  nameString = CFStringGetCStringPtr(key, kCFStringEncodingMacRoman);
+  nameLen = CFStringGetLength(key) + 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>";
+  }
   
   // Get the OF variable's type.
   typeID = CFGetTypeID(value);
   
-  if        (typeID == CFBooleanGetTypeID()) {
+  if (typeID == CFBooleanGetTypeID()) {
     if (CFBooleanGetValue(value)) valueString = "true";
     else valueString = "false";
   } else if (typeID == CFNumberGetTypeID()) {
@@ -487,7 +581,14 @@ static void PrintOFVariable(const void *key, const void *value, void *context)
     else sprintf(numberBuffer, "0x%x", number);
     valueString = numberBuffer;
   } else if (typeID == CFStringGetTypeID()) {
-    valueString = CFStringGetCStringPtr(value, kCFStringEncodingMacRoman);
+    valueLen = CFStringGetLength(value) + 1;
+    valueBuffer = malloc(valueLen + 1);
+    if ( valueBuffer && CFStringGetCString(value, valueBuffer, valueLen, kCFStringEncodingUTF8) )
+      valueString = valueBuffer;
+    else {
+      warnx("Unable to convert value to C string");
+      valueString = "<UNPRINTABLE>";
+    }
   } else if (typeID == CFDataGetTypeID()) {
     length = CFDataGetLength(value);
     if (length == 0) valueString = "";
@@ -507,14 +608,45 @@ static void PrintOFVariable(const void *key, const void *value, void *context)
        valueString = dataBuffer;
       }
     }
-  } else return;
+  } 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(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) {
+    errx(1, "Error clearing firmware variables: %s", mach_error_string(result));
+  }
+}
 
 // ConvertValueToCFTypeRef(typeID, value)
 //
@@ -535,7 +667,7 @@ static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value)
                              &number);
   } else if (typeID == CFStringGetTypeID()) {
     valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value,
-                                        kCFStringEncodingMacRoman);
+                                        kCFStringEncodingUTF8);
   } else if (typeID == CFDataGetTypeID()) {
     length = strlen(value);
     for (cnt = cnt2 = 0; cnt < length; cnt++, cnt2++) {
@@ -550,9 +682,33 @@ static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value)
        value[cnt2] = number;
       } else value[cnt2] = value[cnt];
     }
-    valueRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, value,
+    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 ) {
+          int nameLen;
+          char *nameBuffer;
+          char *nameString;
+
+          // Get the variable's name.
+          nameLen = CFStringGetLength(key) + 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));
+  }
+}