2 * Copyright (c) 2000 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 IOKit -Wall
27 #include <IOKit/IOKitLib.h>
28 #include <CoreFoundation/CoreFoundation.h>
31 static void Error(char *format
, long item
);
32 static void FatalError(long exitValue
, char *format
, long item
);
33 static void UsageMessage(char *message
);
34 static void ParseFile(char *fileName
);
35 static void SetOrGetOFVariable(char *str
);
36 static kern_return_t
GetOFVariable(char *name
, CFStringRef
*nameRef
,
38 static kern_return_t
SetOFVariable(char *name
, char *value
);
39 static void PrintOFVariables(void);
40 static void PrintOFVariable(const void *key
,const void *value
,void *context
);
41 static CFTypeRef
ConvertValueToCFTypeRef(CFTypeID typeID
, char *value
);
44 static char *gToolName
;
45 static io_registry_entry_t gOptionsRef
;
48 int main(int argc
, char **argv
)
51 char *str
, errorMessage
[256];
53 mach_port_t masterPort
;
55 // Get the name of the command.
56 gToolName
= strrchr(argv
[0], '/');
57 if (gToolName
!= 0) gToolName
++;
58 else gToolName
= argv
[0];
60 result
= IOMasterPort(bootstrap_port
, &masterPort
);
61 if (result
!= KERN_SUCCESS
) {
62 FatalError(-1, "Error (%d) getting the IOMaster port", result
);
66 gOptionsRef
= IORegistryEntryFromPath(masterPort
, "IODeviceTree:/options");
67 if (gOptionsRef
== 0) {
68 FatalError(-1, "Error (%d) getting a reference to /options", -1);
72 for (cnt
= 1; cnt
< argc
; cnt
++) {
74 if (str
[0] == '-' && str
[1] != 0) {
76 for (str
+= 1 ; *str
; str
++) {
84 if (cnt
< argc
&& *argv
[cnt
] != '-') {
87 UsageMessage("missing filename");
92 strcpy(errorMessage
, "no such option as --");
93 errorMessage
[strlen(errorMessage
)-1] = *str
;
94 UsageMessage(errorMessage
);
98 // Other arguments will be Open Firmware variable requests.
99 SetOrGetOFVariable(str
);
103 IOObjectRelease(gOptionsRef
);
109 // Error(format, item)
111 // Print a message on standard error.
113 static void Error(char *format
, long item
)
115 fprintf(stderr
, "%s: ", gToolName
);
116 fprintf(stderr
, format
, item
);
117 fprintf(stderr
, "\n");
121 // FatalError(exitValue, format, item)
123 // Print a message on standard error and exit with value.
125 static void FatalError(long exitValue
, char *format
, long item
)
127 fprintf(stderr
, "%s: ", gToolName
);
128 fprintf(stderr
, format
, item
);
129 fprintf(stderr
, "\n");
135 // UsageMessage(message)
137 // Print the usage information and exit.
139 static void UsageMessage(char *message
)
141 Error("(usage: %s)", (long)message
);
143 printf("%s [-p] [-f filename] name[=value] ...\n", gToolName
);
144 printf("\t-p print all Open Firmware variables\n");
145 printf("\t-f set Open Firmware variables from a text file\n");
146 printf("\tname=value set named variable\n");
147 printf("\tname print variable\n");
148 printf("Note that arguments and options are executed in order.\n");
154 // States for ParseFile.
165 kMaxStringSize
= 0x800,
170 // ParseFile(fileName)
172 // Open and parse the specified file.
174 static void ParseFile(char *fileName
)
176 long state
, tc
, ni
= 0, vi
= 0;
177 char name
[kMaxNameSize
];
178 char value
[kMaxStringSize
];
181 patches
= fopen(fileName
, "r");
183 FatalError(errno
, "Couldn't open patch file - '%s'", (long)fileName
);
186 state
= kFirstColumn
;
187 while ((tc
= getc(patches
)) != EOF
) {
193 state
= kScanComment
;
194 } else if (tc
== '\n') {
195 // state stays kFirstColumn.
196 } else if (isspace(tc
)) {
199 state
= kCollectName
;
206 state
= kFirstColumn
;
208 // state stays kScanComment.
214 state
= kFirstColumn
;
215 } else if (isspace(tc
)) {
216 // state stays kFindName.
218 state
= kCollectName
;
226 Error("Name must be followed by white space - '%s'", (long)name
);
227 state
= kFirstColumn
;
228 } else if (isspace(tc
)) {
232 // state staus kCollectName.
237 case kContinueValue
:
240 } else if (isspace(tc
)) {
241 // state stays kFindValue or kContinueValue.
243 state
= kCollectValue
;
250 if (value
[vi
-1] == '\\') {
252 state
= kContinueValue
;
257 // state stays kCollectValue.
263 if (state
== kSetenv
) {
266 if (SetOFVariable(name
, value
) != KERN_SUCCESS
) {
267 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name
);
269 state
= kFirstColumn
;
273 if (state
!= kFirstColumn
) {
274 FatalError(-1, "Last line ended abruptly", 0);
279 // SetOrGetOFVariable(str)
281 // Parse the input string the set or get the specified
282 // Open Firmware variable.
284 static void SetOrGetOFVariable(char *str
)
291 kern_return_t result
;
293 // OF variable name is first.
296 // Find the equal sign for set
307 // On sets, the OF variable's value follows the equal sign.
310 result
= SetOFVariable(name
, value
);
311 if (result
!= KERN_SUCCESS
) {
312 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name
);
315 result
= GetOFVariable(name
, &nameRef
, &valueRef
);
316 if (result
!= KERN_SUCCESS
) {
317 FatalError(-1, "Error (-1) getting variable - '%s'", (long)name
);
320 PrintOFVariable(nameRef
, valueRef
, 0);
327 // GetOFVariable(name, nameRef, valueRef)
329 // Get the named Open Firmware variable.
330 // Return it and it's symbol in valueRef and nameRef.
332 static kern_return_t
GetOFVariable(char *name
, CFStringRef
*nameRef
,
335 *nameRef
= CFStringCreateWithCString(kCFAllocatorDefault
, name
,
336 kCFStringEncodingMacRoman
);
338 FatalError(-1, "Error CFString for key %s", (long)name
);
341 *valueRef
= IORegistryEntryCreateCFProperty(gOptionsRef
, *nameRef
, 0, 0);
342 if (*valueRef
== 0) return -1;
348 // SetOFVariable(name, value)
350 // Set or create an Open Firmware variable with name and value.
352 static kern_return_t
SetOFVariable(char *name
, char *value
)
357 kern_return_t result
;
359 nameRef
= CFStringCreateWithCString(kCFAllocatorDefault
, name
,
360 kCFStringEncodingMacRoman
);
362 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name
);
365 valueRef
= IORegistryEntryCreateCFProperty(gOptionsRef
, nameRef
, 0, 0);
367 typeID
= CFGetTypeID(valueRef
);
369 } else typeID
= CFDataGetTypeID();
371 valueRef
= ConvertValueToCFTypeRef(typeID
, value
);
373 FatalError(-1, "Error (-1) creating CFTypeRef for value %s",(long)value
);
376 result
= IORegistryEntrySetCFProperty(gOptionsRef
, nameRef
, valueRef
);
384 // PrintOFVariables()
386 // Print all of the Open Firmware variables.
388 static void PrintOFVariables()
390 kern_return_t result
;
391 CFMutableDictionaryRef dict
;
393 result
= IORegistryEntryCreateCFProperties(gOptionsRef
, &dict
, 0, 0);
394 if (result
!= KERN_SUCCESS
) {
395 FatalError(-1, "Error (%d) getting the Open Firmware variables", result
);
397 CFDictionaryApplyFunction(dict
, &PrintOFVariable
, 0);
403 // PrintOFVariable(key, value, context)
405 // Print the given Open Firmware variable.
407 static void PrintOFVariable(const void *key
, const void *value
, void *context
)
410 const char *nameString
;
411 char numberBuffer
[10];
412 char *dataPtr
, dataChar
;
413 char *dataBuffer
= 0;
414 char *valueString
= 0;
415 unsigned long number
, length
;
418 // Get the OF variable's name.
419 nameString
= CFStringGetCStringPtr(key
, kCFStringEncodingMacRoman
);
421 // Get the OF variable's type.
422 typeID
= CFGetTypeID(value
);
424 if (typeID
== CFBooleanGetTypeID()) {
425 if (CFBooleanGetValue(value
)) valueString
= "true";
426 else valueString
= "false";
427 } else if (typeID
== CFNumberGetTypeID()) {
428 CFNumberGetValue(value
, kCFNumberSInt32Type
, &number
);
429 if (number
== 0xFFFFFFFF) sprintf(numberBuffer
, "-1");
430 else if (number
< 1000) sprintf(numberBuffer
, "%d", number
);
431 else sprintf(numberBuffer
, "0x%x", number
);
432 valueString
= numberBuffer
;
433 } else if (typeID
== CFStringGetTypeID()) {
434 valueString
= CFStringGetCStringPtr(value
, kCFStringEncodingMacRoman
);
435 } else if (typeID
== CFDataGetTypeID()) {
436 length
= CFDataGetLength(value
);
437 if (length
== 0) valueString
= "";
439 dataBuffer
= malloc(length
* 3 + 1);
440 if (dataBuffer
!= 0) {
441 dataPtr
= CFDataGetBytePtr(value
);
442 for (cnt
= cnt2
= 0; cnt
< length
; cnt
++) {
443 dataChar
= dataPtr
[cnt
];
444 if (isprint(dataChar
)) dataBuffer
[cnt2
++] = dataChar
;
446 sprintf(dataBuffer
+ cnt2
, "%%%02x", dataChar
);
450 dataBuffer
[cnt2
] = '\0';
451 valueString
= dataBuffer
;
456 if ((nameString
!= 0) && (valueString
!= 0))
457 printf("%s\t%s\n", nameString
, valueString
);
459 if (dataBuffer
!= 0) free(dataBuffer
);
463 // ConvertValueToCFTypeRef(typeID, value)
465 // Convert the value into a CFType given the typeID.
467 static CFTypeRef
ConvertValueToCFTypeRef(CFTypeID typeID
, char *value
)
469 CFTypeRef valueRef
= 0;
470 long cnt
, cnt2
, length
;
471 unsigned long number
, tmp
;
473 if (typeID
== CFBooleanGetTypeID()) {
474 if (!strcmp("true", value
)) valueRef
= kCFBooleanTrue
;
475 else if (!strcmp("false", value
)) valueRef
= kCFBooleanFalse
;
476 } else if (typeID
== CFNumberGetTypeID()) {
477 number
= strtol(value
, 0, 0);
478 valueRef
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
,
480 } else if (typeID
== CFStringGetTypeID()) {
481 valueRef
= CFStringCreateWithCString(kCFAllocatorDefault
, value
,
482 kCFStringEncodingMacRoman
);
483 } else if (typeID
== CFDataGetTypeID()) {
484 length
= strlen(value
);
485 for (cnt
= cnt2
= 0; cnt
< length
; cnt
++, cnt2
++) {
486 if (value
[cnt
] == '%') {
487 if (!ishexnumber(value
[cnt
+ 1]) ||
488 !ishexnumber(value
[cnt
+ 2])) return 0;
489 number
= toupper(value
[++cnt
]) - '0';
490 if (number
> 9) number
-= 7;
491 tmp
= toupper(value
[++cnt
]) - '0';
492 if (tmp
> 9) tmp
-= 7;
493 number
= (number
<< 4) + tmp
;
494 value
[cnt2
] = number
;
495 } else value
[cnt2
] = value
[cnt
];
497 valueRef
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, value
,
498 cnt2
, kCFAllocatorDefault
);