2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall
27 #include <IOKit/IOKitLib.h>
28 #include <IOKit/IOKitKeys.h>
29 #include <CoreFoundation/CoreFoundation.h>
32 static void Error(char *format
, long item
);
33 static void FatalError(long exitValue
, char *format
, long item
);
34 static void UsageMessage(char *message
);
35 static void ParseFile(char *fileName
);
36 static void ParseXMLFile(char *fileName
);
37 static void SetOrGetOFVariable(char *str
);
38 static kern_return_t
GetOFVariable(char *name
, CFStringRef
*nameRef
,
40 static kern_return_t
SetOFVariable(char *name
, char *value
);
41 static void DeleteOFVariable(char *name
);
42 static void PrintOFVariables(void);
43 static void PrintOFVariable(const void *key
,const void *value
,void *context
);
44 static void SetOFVariableFromFile(const void *key
, const void *value
, void *context
);
45 static void ClearOFVariables(void);
46 static void ClearOFVariable(const void *key
,const void *value
,void *context
);
47 static CFTypeRef
ConvertValueToCFTypeRef(CFTypeID typeID
, char *value
);
50 static char *gToolName
;
51 static io_registry_entry_t gOptionsRef
;
55 int main(int argc
, char **argv
)
58 char *str
, errorMessage
[256];
60 mach_port_t masterPort
;
62 // Get the name of the command.
63 gToolName
= strrchr(argv
[0], '/');
64 if (gToolName
!= 0) gToolName
++;
65 else gToolName
= argv
[0];
67 result
= IOMasterPort(bootstrap_port
, &masterPort
);
68 if (result
!= KERN_SUCCESS
) {
69 FatalError(-1, "Error (%d) getting the IOMaster port", result
);
73 gOptionsRef
= IORegistryEntryFromPath(masterPort
, "IODeviceTree:/options");
74 if (gOptionsRef
== 0) {
75 FatalError(-1, "nvram is not supported on this system.", -1);
79 for (cnt
= 1; cnt
< argc
; cnt
++) {
81 if (str
[0] == '-' && str
[1] != 0) {
83 for (str
+= 1 ; *str
; str
++) {
95 if (cnt
< argc
&& *argv
[cnt
] != '-') {
98 UsageMessage("missing filename");
104 if (cnt
< argc
&& *argv
[cnt
] != '-') {
105 DeleteOFVariable(argv
[cnt
]);
107 UsageMessage("missing name");
116 strcpy(errorMessage
, "no such option as --");
117 errorMessage
[strlen(errorMessage
)-1] = *str
;
118 UsageMessage(errorMessage
);
122 // Other arguments will be firmware variable requests.
123 SetOrGetOFVariable(str
);
127 IOObjectRelease(gOptionsRef
);
133 // Error(format, item)
135 // Print a message on standard error.
137 static void Error(char *format
, long item
)
139 fprintf(stderr
, "%s: ", gToolName
);
140 fprintf(stderr
, format
, item
);
141 fprintf(stderr
, "\n");
145 // FatalError(exitValue, format, item)
147 // Print a message on standard error and exit with value.
149 static void FatalError(long exitValue
, char *format
, long item
)
151 fprintf(stderr
, "%s: ", gToolName
);
152 fprintf(stderr
, format
, item
);
153 fprintf(stderr
, "\n");
159 // UsageMessage(message)
161 // Print the usage information and exit.
163 static void UsageMessage(char *message
)
165 Error("(usage: %s)", (long)message
);
167 printf("%s [-x] [-p] [-f filename] [-d name] name[=value] ...\n", gToolName
);
168 printf("\t-x use XML format for printing or reading variables\n");
169 printf("\t (must appear before -p or -f)\n");
170 printf("\t-p print all firmware variables\n");
171 printf("\t-f set firmware variables from a text file\n");
172 printf("\t-d delete the named variable\n");
173 printf("\t-c delete all variables\n");
174 printf("\tname=value set named variable\n");
175 printf("\tname print variable\n");
176 printf("Note that arguments and options are executed in order.\n");
182 // States for ParseFile.
193 kMaxStringSize
= 0x800,
198 // ParseFile(fileName)
200 // Open and parse the specified file.
202 static void ParseFile(char *fileName
)
204 long state
, tc
, ni
= 0, vi
= 0;
205 char name
[kMaxNameSize
];
206 char value
[kMaxStringSize
];
210 ParseXMLFile(fileName
);
214 patches
= fopen(fileName
, "r");
216 FatalError(errno
, "Couldn't open patch file - '%s'", (long)fileName
);
219 state
= kFirstColumn
;
220 while ((tc
= getc(patches
)) != EOF
) {
221 if(ni
==(kMaxNameSize
-1))
222 FatalError(-1,"Name exceeded max length of %d",kMaxNameSize
);
223 if(vi
==(kMaxStringSize
-1))
224 FatalError(-1,"Value exceeded max length of %d",kMaxStringSize
);
230 state
= kScanComment
;
231 } else if (tc
== '\n') {
232 // state stays kFirstColumn.
233 } else if (isspace(tc
)) {
236 state
= kCollectName
;
243 state
= kFirstColumn
;
245 // state stays kScanComment.
251 state
= kFirstColumn
;
252 } else if (isspace(tc
)) {
253 // state stays kFindName.
255 state
= kCollectName
;
263 Error("Name must be followed by white space - '%s'", (long)name
);
264 state
= kFirstColumn
;
265 } else if (isspace(tc
)) {
269 // state staus kCollectName.
274 case kContinueValue
:
277 } else if (isspace(tc
)) {
278 // state stays kFindValue or kContinueValue.
280 state
= kCollectValue
;
287 if (value
[vi
-1] == '\\') {
289 state
= kContinueValue
;
294 // state stays kCollectValue.
300 if (state
== kSetenv
) {
303 if (SetOFVariable(name
, value
) != KERN_SUCCESS
) {
304 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name
);
306 state
= kFirstColumn
;
310 if (state
!= kFirstColumn
) {
311 FatalError(-1, "Last line ended abruptly", 0);
316 // ParseXMLFile(fileName)
318 // Open and parse the specified file in XML format,
319 // and set variables appropriately.
321 static void ParseXMLFile(char *fileName
)
323 CFPropertyListRef plist
;
324 CFURLRef fileURL
= NULL
;
325 CFStringRef filePath
= NULL
;
326 CFStringRef errorString
= NULL
;
327 CFDataRef data
= NULL
;
328 SInt32 errorCode
= 0;
330 filePath
= CFStringCreateWithCString(kCFAllocatorDefault
, fileName
, kCFStringEncodingUTF8
);
331 if (filePath
== NULL
) {
332 FatalError(-1, "Could not create file path string", 0);
335 // Create a URL that specifies the file we will create to
336 // hold the XML data.
337 fileURL
= CFURLCreateWithFileSystemPath( kCFAllocatorDefault
,
339 kCFURLPOSIXPathStyle
,
340 false /* not a directory */ );
341 if (fileURL
== NULL
) {
342 FatalError(-1, "Could not create file path URL", 0);
347 if (! CFURLCreateDataAndPropertiesFromResource(
353 &errorCode
) || data
== NULL
) {
354 FatalError(-1, "Error reading XML file (%d)", errorCode
);
359 plist
= CFPropertyListCreateFromXMLData(kCFAllocatorDefault
,
361 kCFPropertyListImmutable
,
367 FatalError(-1, "Error parsing XML file", 0);
370 if (errorString
!= NULL
) {
371 FatalError(-1, "Error parsing XML file: %s", (long)CFStringGetCStringPtr(errorString
, kCFStringEncodingUTF8
));
374 CFDictionaryApplyFunction(plist
, &SetOFVariableFromFile
, 0);
379 // SetOrGetOFVariable(str)
381 // Parse the input string, then set or get the specified
382 // firmware variable.
384 static void SetOrGetOFVariable(char *str
)
391 kern_return_t result
;
393 // OF variable name is first.
396 // Find the equal sign for set
407 // On sets, the OF variable's value follows the equal sign.
410 result
= SetOFVariable(name
, value
);
411 if (result
!= KERN_SUCCESS
) {
412 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name
);
415 result
= GetOFVariable(name
, &nameRef
, &valueRef
);
416 if (result
!= KERN_SUCCESS
) {
417 FatalError(-1, "Error (-1) getting variable - '%s'", (long)name
);
420 PrintOFVariable(nameRef
, valueRef
, 0);
427 // GetOFVariable(name, nameRef, valueRef)
429 // Get the named firmware variable.
430 // Return it and it's symbol in valueRef and nameRef.
432 static kern_return_t
GetOFVariable(char *name
, CFStringRef
*nameRef
,
435 *nameRef
= CFStringCreateWithCString(kCFAllocatorDefault
, name
,
436 kCFStringEncodingUTF8
);
438 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name
);
441 *valueRef
= IORegistryEntryCreateCFProperty(gOptionsRef
, *nameRef
, 0, 0);
442 if (*valueRef
== 0) return -1;
448 // SetOFVariable(name, value)
450 // Set or create an firmware variable with name and value.
452 static kern_return_t
SetOFVariable(char *name
, char *value
)
457 kern_return_t result
;
459 nameRef
= CFStringCreateWithCString(kCFAllocatorDefault
, name
,
460 kCFStringEncodingUTF8
);
462 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name
);
465 valueRef
= IORegistryEntryCreateCFProperty(gOptionsRef
, nameRef
, 0, 0);
467 typeID
= CFGetTypeID(valueRef
);
470 valueRef
= ConvertValueToCFTypeRef(typeID
, value
);
472 FatalError(-1, "Error (-1) creating CFTypeRef for value %s",(long)value
);
473 } result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
476 // In the default case, try data, string, number, then boolean.
478 valueRef
= ConvertValueToCFTypeRef(CFDataGetTypeID(), value
);
480 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
481 if (result
== KERN_SUCCESS
) break;
484 valueRef
= ConvertValueToCFTypeRef(CFStringGetTypeID(), value
);
486 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
487 if (result
== KERN_SUCCESS
) break;
490 valueRef
= ConvertValueToCFTypeRef(CFNumberGetTypeID(), value
);
492 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
493 if (result
== KERN_SUCCESS
) break;
496 valueRef
= ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value
);
498 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
499 if (result
== KERN_SUCCESS
) break;
513 // DeleteOFVariable(name)
515 // Delete the named firmware variable.
518 static void DeleteOFVariable(char *name
)
520 SetOFVariable(kIONVRAMDeletePropertyKey
, name
);
524 // PrintOFVariables()
526 // Print all of the firmware variables.
528 static void PrintOFVariables()
530 kern_return_t result
;
531 CFMutableDictionaryRef dict
;
533 result
= IORegistryEntryCreateCFProperties(gOptionsRef
, &dict
, 0, 0);
534 if (result
!= KERN_SUCCESS
) {
535 FatalError(-1, "Error (%d) getting the firmware variables", result
);
541 data
= CFPropertyListCreateXMLData( kCFAllocatorDefault
, dict
);
543 FatalError(-1, "Error (%d) converting variables to xml", result
);
546 fwrite(CFDataGetBytePtr(data
), sizeof(UInt8
), CFDataGetLength(data
), stdout
);
552 CFDictionaryApplyFunction(dict
, &PrintOFVariable
, 0);
559 // PrintOFVariable(key, value, context)
561 // Print the given firmware variable.
563 static void PrintOFVariable(const void *key
, const void *value
, void *context
)
567 char *nameBuffer
= 0;
568 const char *nameString
;
569 char numberBuffer
[10];
570 const uint8_t *dataPtr
;
572 char *dataBuffer
= 0;
574 char *valueBuffer
= 0;
575 const char *valueString
= 0;
576 uint32_t number
, length
;
579 // Get the OF variable's name.
580 nameLen
= CFStringGetLength(key
) + 1;
581 nameBuffer
= malloc(nameLen
);
582 if( nameBuffer
&& CFStringGetCString(key
, nameBuffer
, nameLen
, kCFStringEncodingUTF8
) )
583 nameString
= nameBuffer
;
585 Error("Error (-1) Unable to convert property name to C string", 0);
586 nameString
= "<UNPRINTABLE>";
589 // Get the OF variable's type.
590 typeID
= CFGetTypeID(value
);
592 if (typeID
== CFBooleanGetTypeID()) {
593 if (CFBooleanGetValue(value
)) valueString
= "true";
594 else valueString
= "false";
595 } else if (typeID
== CFNumberGetTypeID()) {
596 CFNumberGetValue(value
, kCFNumberSInt32Type
, &number
);
597 if (number
== 0xFFFFFFFF) sprintf(numberBuffer
, "-1");
598 else if (number
< 1000) sprintf(numberBuffer
, "%d", number
);
599 else sprintf(numberBuffer
, "0x%x", number
);
600 valueString
= numberBuffer
;
601 } else if (typeID
== CFStringGetTypeID()) {
602 valueLen
= CFStringGetLength(value
) + 1;
603 valueBuffer
= malloc(valueLen
+ 1);
604 if ( valueBuffer
&& CFStringGetCString(value
, valueBuffer
, valueLen
, kCFStringEncodingUTF8
) )
605 valueString
= valueBuffer
;
607 Error("Error (-1) Unable to convert value to C string", 0);
608 valueString
= "<UNPRINTABLE>";
610 } else if (typeID
== CFDataGetTypeID()) {
611 length
= CFDataGetLength(value
);
612 if (length
== 0) valueString
= "";
614 dataBuffer
= malloc(length
* 3 + 1);
615 if (dataBuffer
!= 0) {
616 dataPtr
= CFDataGetBytePtr(value
);
617 for (cnt
= cnt2
= 0; cnt
< length
; cnt
++) {
618 dataChar
= dataPtr
[cnt
];
619 if (isprint(dataChar
)) dataBuffer
[cnt2
++] = dataChar
;
621 sprintf(dataBuffer
+ cnt2
, "%%%02x", dataChar
);
625 dataBuffer
[cnt2
] = '\0';
626 valueString
= dataBuffer
;
630 valueString
="<INVALID>";
633 if ((nameString
!= 0) && (valueString
!= 0))
634 printf("%s\t%s\n", nameString
, valueString
);
636 if (dataBuffer
!= 0) free(dataBuffer
);
637 if (nameBuffer
!= 0) free(nameBuffer
);
638 if (valueBuffer
!= 0) free(valueBuffer
);
641 // ClearOFVariables()
643 // Deletes all OF variables
645 static void ClearOFVariables(void)
647 kern_return_t result
;
648 CFMutableDictionaryRef dict
;
650 result
= IORegistryEntryCreateCFProperties(gOptionsRef
, &dict
, 0, 0);
651 if (result
!= KERN_SUCCESS
) {
652 FatalError(-1, "Error (%d) getting the firmware variables", result
);
654 CFDictionaryApplyFunction(dict
, &ClearOFVariable
, 0);
659 static void ClearOFVariable(const void *key
, const void *value
, void *context
)
661 kern_return_t result
;
662 result
= IORegistryEntrySetCFProperty(gOptionsRef
,
663 CFSTR(kIONVRAMDeletePropertyKey
), key
);
664 if (result
!= KERN_SUCCESS
) {
665 FatalError(-1, "Error (%d) clearing firmware variables", result
);
669 // ConvertValueToCFTypeRef(typeID, value)
671 // Convert the value into a CFType given the typeID.
673 static CFTypeRef
ConvertValueToCFTypeRef(CFTypeID typeID
, char *value
)
675 CFTypeRef valueRef
= 0;
676 long cnt
, cnt2
, length
;
677 unsigned long number
, tmp
;
679 if (typeID
== CFBooleanGetTypeID()) {
680 if (!strcmp("true", value
)) valueRef
= kCFBooleanTrue
;
681 else if (!strcmp("false", value
)) valueRef
= kCFBooleanFalse
;
682 } else if (typeID
== CFNumberGetTypeID()) {
683 number
= strtol(value
, 0, 0);
684 valueRef
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
,
686 } else if (typeID
== CFStringGetTypeID()) {
687 valueRef
= CFStringCreateWithCString(kCFAllocatorDefault
, value
,
688 kCFStringEncodingUTF8
);
689 } else if (typeID
== CFDataGetTypeID()) {
690 length
= strlen(value
);
691 for (cnt
= cnt2
= 0; cnt
< length
; cnt
++, cnt2
++) {
692 if (value
[cnt
] == '%') {
693 if (!ishexnumber(value
[cnt
+ 1]) ||
694 !ishexnumber(value
[cnt
+ 2])) return 0;
695 number
= toupper(value
[++cnt
]) - '0';
696 if (number
> 9) number
-= 7;
697 tmp
= toupper(value
[++cnt
]) - '0';
698 if (tmp
> 9) tmp
-= 7;
699 number
= (number
<< 4) + tmp
;
700 value
[cnt2
] = number
;
701 } else value
[cnt2
] = value
[cnt
];
703 valueRef
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)value
,
704 cnt2
, kCFAllocatorDefault
);
710 static void SetOFVariableFromFile(const void *key
, const void *value
, void *context
)
712 kern_return_t result
;
714 result
= IORegistryEntrySetCFProperty(gOptionsRef
, key
, value
);
715 if ( result
!= KERN_SUCCESS
) {
720 // Get the variable's name.
721 nameLen
= CFStringGetLength(key
) + 1;
722 nameBuffer
= malloc(nameLen
);
723 if( nameBuffer
&& CFStringGetCString(key
, nameBuffer
, nameLen
, kCFStringEncodingUTF8
) )
724 nameString
= nameBuffer
;
726 Error("Error (-1) Unable to convert property name to C string", 0);
727 nameString
= "<UNPRINTABLE>";
729 FatalError(-1, "Error (-1) setting variable - '%s'", (long)nameString
);