2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall
30 #include <IOKit/IOKitLib.h>
31 #include <IOKit/IOKitKeys.h>
32 #include <CoreFoundation/CoreFoundation.h>
35 static void Error(char *format
, long item
);
36 static void FatalError(long exitValue
, char *format
, long item
);
37 static void UsageMessage(char *message
);
38 static void ParseFile(char *fileName
);
39 static void SetOrGetOFVariable(char *str
);
40 static kern_return_t
GetOFVariable(char *name
, CFStringRef
*nameRef
,
42 static kern_return_t
SetOFVariable(char *name
, char *value
);
43 static void DeleteOFVariable(char *name
);
44 static void PrintOFVariables(void);
45 static void PrintOFVariable(const void *key
,const void *value
,void *context
);
46 static CFTypeRef
ConvertValueToCFTypeRef(CFTypeID typeID
, char *value
);
49 static char *gToolName
;
50 static io_registry_entry_t gOptionsRef
;
53 int main(int argc
, char **argv
)
56 char *str
, errorMessage
[256];
58 mach_port_t masterPort
;
60 // Get the name of the command.
61 gToolName
= strrchr(argv
[0], '/');
62 if (gToolName
!= 0) gToolName
++;
63 else gToolName
= argv
[0];
65 result
= IOMasterPort(bootstrap_port
, &masterPort
);
66 if (result
!= KERN_SUCCESS
) {
67 FatalError(-1, "Error (%d) getting the IOMaster port", result
);
71 gOptionsRef
= IORegistryEntryFromPath(masterPort
, "IODeviceTree:/options");
72 if (gOptionsRef
== 0) {
73 FatalError(-1, "Error (%d) getting a reference to /options", -1);
77 for (cnt
= 1; cnt
< argc
; cnt
++) {
79 if (str
[0] == '-' && str
[1] != 0) {
81 for (str
+= 1 ; *str
; str
++) {
89 if (cnt
< argc
&& *argv
[cnt
] != '-') {
92 UsageMessage("missing filename");
98 if (cnt
< argc
&& *argv
[cnt
] != '-') {
99 DeleteOFVariable(argv
[cnt
]);
101 UsageMessage("missing name");
106 strcpy(errorMessage
, "no such option as --");
107 errorMessage
[strlen(errorMessage
)-1] = *str
;
108 UsageMessage(errorMessage
);
112 // Other arguments will be Open Firmware variable requests.
113 SetOrGetOFVariable(str
);
117 IOObjectRelease(gOptionsRef
);
123 // Error(format, item)
125 // Print a message on standard error.
127 static void Error(char *format
, long item
)
129 fprintf(stderr
, "%s: ", gToolName
);
130 fprintf(stderr
, format
, item
);
131 fprintf(stderr
, "\n");
135 // FatalError(exitValue, format, item)
137 // Print a message on standard error and exit with value.
139 static void FatalError(long exitValue
, char *format
, long item
)
141 fprintf(stderr
, "%s: ", gToolName
);
142 fprintf(stderr
, format
, item
);
143 fprintf(stderr
, "\n");
149 // UsageMessage(message)
151 // Print the usage information and exit.
153 static void UsageMessage(char *message
)
155 Error("(usage: %s)", (long)message
);
157 printf("%s [-p] [-f filename] [-d name] name[=value] ...\n", gToolName
);
158 printf("\t-p print all Open Firmware variables\n");
159 printf("\t-f set Open Firmware variables from a text file\n");
160 printf("\t-d delete the named variable\n");
161 printf("\tname=value set named variable\n");
162 printf("\tname print variable\n");
163 printf("Note that arguments and options are executed in order.\n");
169 // States for ParseFile.
180 kMaxStringSize
= 0x800,
185 // ParseFile(fileName)
187 // Open and parse the specified file.
189 static void ParseFile(char *fileName
)
191 long state
, tc
, ni
= 0, vi
= 0;
192 char name
[kMaxNameSize
];
193 char value
[kMaxStringSize
];
196 patches
= fopen(fileName
, "r");
198 FatalError(errno
, "Couldn't open patch file - '%s'", (long)fileName
);
201 state
= kFirstColumn
;
202 while ((tc
= getc(patches
)) != EOF
) {
208 state
= kScanComment
;
209 } else if (tc
== '\n') {
210 // state stays kFirstColumn.
211 } else if (isspace(tc
)) {
214 state
= kCollectName
;
221 state
= kFirstColumn
;
223 // state stays kScanComment.
229 state
= kFirstColumn
;
230 } else if (isspace(tc
)) {
231 // state stays kFindName.
233 state
= kCollectName
;
241 Error("Name must be followed by white space - '%s'", (long)name
);
242 state
= kFirstColumn
;
243 } else if (isspace(tc
)) {
247 // state staus kCollectName.
252 case kContinueValue
:
255 } else if (isspace(tc
)) {
256 // state stays kFindValue or kContinueValue.
258 state
= kCollectValue
;
265 if (value
[vi
-1] == '\\') {
267 state
= kContinueValue
;
272 // state stays kCollectValue.
278 if (state
== kSetenv
) {
281 if (SetOFVariable(name
, value
) != KERN_SUCCESS
) {
282 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name
);
284 state
= kFirstColumn
;
288 if (state
!= kFirstColumn
) {
289 FatalError(-1, "Last line ended abruptly", 0);
294 // SetOrGetOFVariable(str)
296 // Parse the input string the set or get the specified
297 // Open Firmware variable.
299 static void SetOrGetOFVariable(char *str
)
306 kern_return_t result
;
308 // OF variable name is first.
311 // Find the equal sign for set
322 // On sets, the OF variable's value follows the equal sign.
325 result
= SetOFVariable(name
, value
);
326 if (result
!= KERN_SUCCESS
) {
327 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name
);
330 result
= GetOFVariable(name
, &nameRef
, &valueRef
);
331 if (result
!= KERN_SUCCESS
) {
332 FatalError(-1, "Error (-1) getting variable - '%s'", (long)name
);
335 PrintOFVariable(nameRef
, valueRef
, 0);
342 // GetOFVariable(name, nameRef, valueRef)
344 // Get the named Open Firmware variable.
345 // Return it and it's symbol in valueRef and nameRef.
347 static kern_return_t
GetOFVariable(char *name
, CFStringRef
*nameRef
,
350 *nameRef
= CFStringCreateWithCString(kCFAllocatorDefault
, name
,
351 kCFStringEncodingMacRoman
);
353 FatalError(-1, "Error CFString for key %s", (long)name
);
356 *valueRef
= IORegistryEntryCreateCFProperty(gOptionsRef
, *nameRef
, 0, 0);
357 if (*valueRef
== 0) return -1;
363 // SetOFVariable(name, value)
365 // Set or create an Open Firmware variable with name and value.
367 static kern_return_t
SetOFVariable(char *name
, char *value
)
372 kern_return_t result
;
374 nameRef
= CFStringCreateWithCString(kCFAllocatorDefault
, name
,
375 kCFStringEncodingMacRoman
);
377 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name
);
380 valueRef
= IORegistryEntryCreateCFProperty(gOptionsRef
, nameRef
, 0, 0);
382 typeID
= CFGetTypeID(valueRef
);
385 valueRef
= ConvertValueToCFTypeRef(typeID
, value
);
387 FatalError(-1, "Error (-1) creating CFTypeRef for value %s",(long)value
);
388 } result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
391 // In the default case, try data, string, number, then boolean.
393 valueRef
= ConvertValueToCFTypeRef(CFDataGetTypeID(), value
);
395 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
396 if (result
== KERN_SUCCESS
) break;
399 valueRef
= ConvertValueToCFTypeRef(CFStringGetTypeID(), value
);
401 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
402 if (result
== KERN_SUCCESS
) break;
405 valueRef
= ConvertValueToCFTypeRef(CFNumberGetTypeID(), value
);
407 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
408 if (result
== KERN_SUCCESS
) break;
411 valueRef
= ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value
);
413 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
414 if (result
== KERN_SUCCESS
) break;
428 // DeleteOFVariable(name)
430 // Delete the named Open Firmware variable.
433 static void DeleteOFVariable(char *name
)
435 SetOFVariable(kIONVRAMDeletePropertyKey
, name
);
439 // PrintOFVariables()
441 // Print all of the Open Firmware variables.
443 static void PrintOFVariables()
445 kern_return_t result
;
446 CFMutableDictionaryRef dict
;
448 result
= IORegistryEntryCreateCFProperties(gOptionsRef
, &dict
, 0, 0);
449 if (result
!= KERN_SUCCESS
) {
450 FatalError(-1, "Error (%d) getting the Open Firmware variables", result
);
452 CFDictionaryApplyFunction(dict
, &PrintOFVariable
, 0);
458 // PrintOFVariable(key, value, context)
460 // Print the given Open Firmware variable.
462 static void PrintOFVariable(const void *key
, const void *value
, void *context
)
465 const char *nameString
;
466 char numberBuffer
[10];
467 const uint8_t *dataPtr
;
469 char *dataBuffer
= 0;
470 const char *valueString
= 0;
471 uint32_t number
, length
;
474 // Get the OF variable's name.
475 nameString
= CFStringGetCStringPtr(key
, kCFStringEncodingMacRoman
);
477 // Get the OF variable's type.
478 typeID
= CFGetTypeID(value
);
480 if (typeID
== CFBooleanGetTypeID()) {
481 if (CFBooleanGetValue(value
)) valueString
= "true";
482 else valueString
= "false";
483 } else if (typeID
== CFNumberGetTypeID()) {
484 CFNumberGetValue(value
, kCFNumberSInt32Type
, &number
);
485 if (number
== 0xFFFFFFFF) sprintf(numberBuffer
, "-1");
486 else if (number
< 1000) sprintf(numberBuffer
, "%d", number
);
487 else sprintf(numberBuffer
, "0x%x", number
);
488 valueString
= numberBuffer
;
489 } else if (typeID
== CFStringGetTypeID()) {
490 valueString
= CFStringGetCStringPtr(value
, kCFStringEncodingMacRoman
);
491 } else if (typeID
== CFDataGetTypeID()) {
492 length
= CFDataGetLength(value
);
493 if (length
== 0) valueString
= "";
495 dataBuffer
= malloc(length
* 3 + 1);
496 if (dataBuffer
!= 0) {
497 dataPtr
= CFDataGetBytePtr(value
);
498 for (cnt
= cnt2
= 0; cnt
< length
; cnt
++) {
499 dataChar
= dataPtr
[cnt
];
500 if (isprint(dataChar
)) dataBuffer
[cnt2
++] = dataChar
;
502 sprintf(dataBuffer
+ cnt2
, "%%%02x", dataChar
);
506 dataBuffer
[cnt2
] = '\0';
507 valueString
= dataBuffer
;
512 if ((nameString
!= 0) && (valueString
!= 0))
513 printf("%s\t%s\n", nameString
, valueString
);
515 if (dataBuffer
!= 0) free(dataBuffer
);
519 // ConvertValueToCFTypeRef(typeID, value)
521 // Convert the value into a CFType given the typeID.
523 static CFTypeRef
ConvertValueToCFTypeRef(CFTypeID typeID
, char *value
)
525 CFTypeRef valueRef
= 0;
526 long cnt
, cnt2
, length
;
527 unsigned long number
, tmp
;
529 if (typeID
== CFBooleanGetTypeID()) {
530 if (!strcmp("true", value
)) valueRef
= kCFBooleanTrue
;
531 else if (!strcmp("false", value
)) valueRef
= kCFBooleanFalse
;
532 } else if (typeID
== CFNumberGetTypeID()) {
533 number
= strtol(value
, 0, 0);
534 valueRef
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
,
536 } else if (typeID
== CFStringGetTypeID()) {
537 valueRef
= CFStringCreateWithCString(kCFAllocatorDefault
, value
,
538 kCFStringEncodingMacRoman
);
539 } else if (typeID
== CFDataGetTypeID()) {
540 length
= strlen(value
);
541 for (cnt
= cnt2
= 0; cnt
< length
; cnt
++, cnt2
++) {
542 if (value
[cnt
] == '%') {
543 if (!ishexnumber(value
[cnt
+ 1]) ||
544 !ishexnumber(value
[cnt
+ 2])) return 0;
545 number
= toupper(value
[++cnt
]) - '0';
546 if (number
> 9) number
-= 7;
547 tmp
= toupper(value
[++cnt
]) - '0';
548 if (tmp
> 9) tmp
-= 7;
549 number
= (number
<< 4) + tmp
;
550 value
[cnt2
] = number
;
551 } else value
[cnt2
] = value
[cnt
];
553 valueRef
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, value
,
554 cnt2
, kCFAllocatorDefault
);