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 SetOrGetOFVariable(char *str
);
37 static kern_return_t
GetOFVariable(char *name
, CFStringRef
*nameRef
,
39 static kern_return_t
SetOFVariable(char *name
, char *value
);
40 static void DeleteOFVariable(char *name
);
41 static void PrintOFVariables(void);
42 static void PrintOFVariable(const void *key
,const void *value
,void *context
);
43 static CFTypeRef
ConvertValueToCFTypeRef(CFTypeID typeID
, char *value
);
46 static char *gToolName
;
47 static io_registry_entry_t gOptionsRef
;
50 int main(int argc
, char **argv
)
53 char *str
, errorMessage
[256];
55 mach_port_t masterPort
;
57 // Get the name of the command.
58 gToolName
= strrchr(argv
[0], '/');
59 if (gToolName
!= 0) gToolName
++;
60 else gToolName
= argv
[0];
62 result
= IOMasterPort(bootstrap_port
, &masterPort
);
63 if (result
!= KERN_SUCCESS
) {
64 FatalError(-1, "Error (%d) getting the IOMaster port", result
);
68 gOptionsRef
= IORegistryEntryFromPath(masterPort
, "IODeviceTree:/options");
69 if (gOptionsRef
== 0) {
70 FatalError(-1, "nvram is not supported on this system.", -1);
74 for (cnt
= 1; cnt
< argc
; cnt
++) {
76 if (str
[0] == '-' && str
[1] != 0) {
78 for (str
+= 1 ; *str
; str
++) {
86 if (cnt
< argc
&& *argv
[cnt
] != '-') {
89 UsageMessage("missing filename");
95 if (cnt
< argc
&& *argv
[cnt
] != '-') {
96 DeleteOFVariable(argv
[cnt
]);
98 UsageMessage("missing name");
103 strcpy(errorMessage
, "no such option as --");
104 errorMessage
[strlen(errorMessage
)-1] = *str
;
105 UsageMessage(errorMessage
);
109 // Other arguments will be firmware variable requests.
110 SetOrGetOFVariable(str
);
114 IOObjectRelease(gOptionsRef
);
120 // Error(format, item)
122 // Print a message on standard error.
124 static void Error(char *format
, long item
)
126 fprintf(stderr
, "%s: ", gToolName
);
127 fprintf(stderr
, format
, item
);
128 fprintf(stderr
, "\n");
132 // FatalError(exitValue, format, item)
134 // Print a message on standard error and exit with value.
136 static void FatalError(long exitValue
, char *format
, long item
)
138 fprintf(stderr
, "%s: ", gToolName
);
139 fprintf(stderr
, format
, item
);
140 fprintf(stderr
, "\n");
146 // UsageMessage(message)
148 // Print the usage information and exit.
150 static void UsageMessage(char *message
)
152 Error("(usage: %s)", (long)message
);
154 printf("%s [-p] [-f filename] [-d name] name[=value] ...\n", gToolName
);
155 printf("\t-p print all firmware variables\n");
156 printf("\t-f set firmware variables from a text file\n");
157 printf("\t-d delete the named variable\n");
158 printf("\tname=value set named variable\n");
159 printf("\tname print variable\n");
160 printf("Note that arguments and options are executed in order.\n");
166 // States for ParseFile.
177 kMaxStringSize
= 0x800,
182 // ParseFile(fileName)
184 // Open and parse the specified file.
186 static void ParseFile(char *fileName
)
188 long state
, tc
, ni
= 0, vi
= 0;
189 char name
[kMaxNameSize
];
190 char value
[kMaxStringSize
];
193 patches
= fopen(fileName
, "r");
195 FatalError(errno
, "Couldn't open patch file - '%s'", (long)fileName
);
198 state
= kFirstColumn
;
199 while ((tc
= getc(patches
)) != EOF
) {
205 state
= kScanComment
;
206 } else if (tc
== '\n') {
207 // state stays kFirstColumn.
208 } else if (isspace(tc
)) {
211 state
= kCollectName
;
218 state
= kFirstColumn
;
220 // state stays kScanComment.
226 state
= kFirstColumn
;
227 } else if (isspace(tc
)) {
228 // state stays kFindName.
230 state
= kCollectName
;
238 Error("Name must be followed by white space - '%s'", (long)name
);
239 state
= kFirstColumn
;
240 } else if (isspace(tc
)) {
244 // state staus kCollectName.
249 case kContinueValue
:
252 } else if (isspace(tc
)) {
253 // state stays kFindValue or kContinueValue.
255 state
= kCollectValue
;
262 if (value
[vi
-1] == '\\') {
264 state
= kContinueValue
;
269 // state stays kCollectValue.
275 if (state
== kSetenv
) {
278 if (SetOFVariable(name
, value
) != KERN_SUCCESS
) {
279 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name
);
281 state
= kFirstColumn
;
285 if (state
!= kFirstColumn
) {
286 FatalError(-1, "Last line ended abruptly", 0);
291 // SetOrGetOFVariable(str)
293 // Parse the input string, then set or get the specified
294 // firmware variable.
296 static void SetOrGetOFVariable(char *str
)
303 kern_return_t result
;
305 // OF variable name is first.
308 // Find the equal sign for set
319 // On sets, the OF variable's value follows the equal sign.
322 result
= SetOFVariable(name
, value
);
323 if (result
!= KERN_SUCCESS
) {
324 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name
);
327 result
= GetOFVariable(name
, &nameRef
, &valueRef
);
328 if (result
!= KERN_SUCCESS
) {
329 FatalError(-1, "Error (-1) getting variable - '%s'", (long)name
);
332 PrintOFVariable(nameRef
, valueRef
, 0);
339 // GetOFVariable(name, nameRef, valueRef)
341 // Get the named firmware variable.
342 // Return it and it's symbol in valueRef and nameRef.
344 static kern_return_t
GetOFVariable(char *name
, CFStringRef
*nameRef
,
347 *nameRef
= CFStringCreateWithCString(kCFAllocatorDefault
, name
,
348 kCFStringEncodingUTF8
);
350 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name
);
353 *valueRef
= IORegistryEntryCreateCFProperty(gOptionsRef
, *nameRef
, 0, 0);
354 if (*valueRef
== 0) return -1;
360 // SetOFVariable(name, value)
362 // Set or create an firmware variable with name and value.
364 static kern_return_t
SetOFVariable(char *name
, char *value
)
369 kern_return_t result
;
371 nameRef
= CFStringCreateWithCString(kCFAllocatorDefault
, name
,
372 kCFStringEncodingUTF8
);
374 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name
);
377 valueRef
= IORegistryEntryCreateCFProperty(gOptionsRef
, nameRef
, 0, 0);
379 typeID
= CFGetTypeID(valueRef
);
382 valueRef
= ConvertValueToCFTypeRef(typeID
, value
);
384 FatalError(-1, "Error (-1) creating CFTypeRef for value %s",(long)value
);
385 } result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
388 // In the default case, try data, string, number, then boolean.
390 valueRef
= ConvertValueToCFTypeRef(CFDataGetTypeID(), value
);
392 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
393 if (result
== KERN_SUCCESS
) break;
396 valueRef
= ConvertValueToCFTypeRef(CFStringGetTypeID(), value
);
398 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
399 if (result
== KERN_SUCCESS
) break;
402 valueRef
= ConvertValueToCFTypeRef(CFNumberGetTypeID(), value
);
404 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
405 if (result
== KERN_SUCCESS
) break;
408 valueRef
= ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value
);
410 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
411 if (result
== KERN_SUCCESS
) break;
425 // DeleteOFVariable(name)
427 // Delete the named firmware variable.
430 static void DeleteOFVariable(char *name
)
432 SetOFVariable(kIONVRAMDeletePropertyKey
, name
);
436 // PrintOFVariables()
438 // Print all of the firmware variables.
440 static void PrintOFVariables()
442 kern_return_t result
;
443 CFMutableDictionaryRef dict
;
445 result
= IORegistryEntryCreateCFProperties(gOptionsRef
, &dict
, 0, 0);
446 if (result
!= KERN_SUCCESS
) {
447 FatalError(-1, "Error (%d) getting the firmware variables", result
);
449 CFDictionaryApplyFunction(dict
, &PrintOFVariable
, 0);
455 // PrintOFVariable(key, value, context)
457 // Print the given firmware variable.
459 static void PrintOFVariable(const void *key
, const void *value
, void *context
)
463 char *nameBuffer
= 0;
464 const char *nameString
;
465 char numberBuffer
[10];
466 const uint8_t *dataPtr
;
468 char *dataBuffer
= 0;
470 char *valueBuffer
= 0;
471 const char *valueString
= 0;
472 uint32_t number
, length
;
475 // Get the OF variable's name.
476 nameLen
= CFStringGetLength(key
) + 1;
477 nameBuffer
= malloc(nameLen
);
478 if( nameBuffer
&& CFStringGetCString(key
, nameBuffer
, nameLen
, kCFStringEncodingUTF8
) )
479 nameString
= nameBuffer
;
481 Error("Error (-1) Unable to convert property name to C string", 0);
482 nameString
= "<UNPRINTABLE>";
485 // Get the OF variable's type.
486 typeID
= CFGetTypeID(value
);
488 if (typeID
== CFBooleanGetTypeID()) {
489 if (CFBooleanGetValue(value
)) valueString
= "true";
490 else valueString
= "false";
491 } else if (typeID
== CFNumberGetTypeID()) {
492 CFNumberGetValue(value
, kCFNumberSInt32Type
, &number
);
493 if (number
== 0xFFFFFFFF) sprintf(numberBuffer
, "-1");
494 else if (number
< 1000) sprintf(numberBuffer
, "%d", number
);
495 else sprintf(numberBuffer
, "0x%x", number
);
496 valueString
= numberBuffer
;
497 } else if (typeID
== CFStringGetTypeID()) {
498 valueLen
= CFStringGetLength(value
) + 1;
499 valueBuffer
= malloc(valueLen
+ 1);
500 if ( valueBuffer
&& CFStringGetCString(value
, valueBuffer
, valueLen
, kCFStringEncodingUTF8
) )
501 valueString
= valueBuffer
;
503 Error("Error (-1) Unable to convert value to C string", 0);
504 valueString
= "<UNPRINTABLE>";
506 } else if (typeID
== CFDataGetTypeID()) {
507 length
= CFDataGetLength(value
);
508 if (length
== 0) valueString
= "";
510 dataBuffer
= malloc(length
* 3 + 1);
511 if (dataBuffer
!= 0) {
512 dataPtr
= CFDataGetBytePtr(value
);
513 for (cnt
= cnt2
= 0; cnt
< length
; cnt
++) {
514 dataChar
= dataPtr
[cnt
];
515 if (isprint(dataChar
)) dataBuffer
[cnt2
++] = dataChar
;
517 sprintf(dataBuffer
+ cnt2
, "%%%02x", dataChar
);
521 dataBuffer
[cnt2
] = '\0';
522 valueString
= dataBuffer
;
526 valueString
="<INVALID>";
529 if ((nameString
!= 0) && (valueString
!= 0))
530 printf("%s\t%s\n", nameString
, valueString
);
532 if (dataBuffer
!= 0) free(dataBuffer
);
533 if (nameBuffer
!= 0) free(nameBuffer
);
534 if (valueBuffer
!= 0) free(valueBuffer
);
538 // ConvertValueToCFTypeRef(typeID, value)
540 // Convert the value into a CFType given the typeID.
542 static CFTypeRef
ConvertValueToCFTypeRef(CFTypeID typeID
, char *value
)
544 CFTypeRef valueRef
= 0;
545 long cnt
, cnt2
, length
;
546 unsigned long number
, tmp
;
548 if (typeID
== CFBooleanGetTypeID()) {
549 if (!strcmp("true", value
)) valueRef
= kCFBooleanTrue
;
550 else if (!strcmp("false", value
)) valueRef
= kCFBooleanFalse
;
551 } else if (typeID
== CFNumberGetTypeID()) {
552 number
= strtol(value
, 0, 0);
553 valueRef
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
,
555 } else if (typeID
== CFStringGetTypeID()) {
556 valueRef
= CFStringCreateWithCString(kCFAllocatorDefault
, value
,
557 kCFStringEncodingUTF8
);
558 } else if (typeID
== CFDataGetTypeID()) {
559 length
= strlen(value
);
560 for (cnt
= cnt2
= 0; cnt
< length
; cnt
++, cnt2
++) {
561 if (value
[cnt
] == '%') {
562 if (!ishexnumber(value
[cnt
+ 1]) ||
563 !ishexnumber(value
[cnt
+ 2])) return 0;
564 number
= toupper(value
[++cnt
]) - '0';
565 if (number
> 9) number
-= 7;
566 tmp
= toupper(value
[++cnt
]) - '0';
567 if (tmp
> 9) tmp
-= 7;
568 number
= (number
<< 4) + tmp
;
569 value
[cnt2
] = number
;
570 } else value
[cnt2
] = value
[cnt
];
572 valueRef
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, value
,
573 cnt2
, kCFAllocatorDefault
);