]> git.saurik.com Git - apple/system_cmds.git/blame - nvram.tproj/nvram.c
system_cmds-433.tar.gz
[apple/system_cmds.git] / nvram.tproj / nvram.c
CommitLineData
1815bff5 1/*
2fc1e207 2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
1815bff5
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
2fc1e207
A
5 *
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.
11 *
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
1815bff5
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2fc1e207
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
1815bff5
A
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
83f6dbe8 23cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall
1815bff5
A
24*/
25
26#include <stdio.h>
27#include <IOKit/IOKitLib.h>
83f6dbe8 28#include <IOKit/IOKitKeys.h>
1815bff5
A
29#include <CoreFoundation/CoreFoundation.h>
30
31// Prototypes
32static void Error(char *format, long item);
33static void FatalError(long exitValue, char *format, long item);
34static void UsageMessage(char *message);
35static void ParseFile(char *fileName);
34d340d7 36static void ParseXMLFile(char *fileName);
1815bff5
A
37static void SetOrGetOFVariable(char *str);
38static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
39 CFTypeRef *valueRef);
40static kern_return_t SetOFVariable(char *name, char *value);
83f6dbe8 41static void DeleteOFVariable(char *name);
1815bff5
A
42static void PrintOFVariables(void);
43static void PrintOFVariable(const void *key,const void *value,void *context);
34d340d7
A
44static void SetOFVariableFromFile(const void *key, const void *value, void *context);
45static void ClearOFVariables(void);
46static void ClearOFVariable(const void *key,const void *value,void *context);
1815bff5
A
47static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value);
48
49// Global Variables
50static char *gToolName;
51static io_registry_entry_t gOptionsRef;
34d340d7 52static bool gUseXML;
1815bff5
A
53
54
55int main(int argc, char **argv)
56{
57 long cnt;
58 char *str, errorMessage[256];
59 kern_return_t result;
60 mach_port_t masterPort;
61
62 // Get the name of the command.
63 gToolName = strrchr(argv[0], '/');
64 if (gToolName != 0) gToolName++;
65 else gToolName = argv[0];
66
67 result = IOMasterPort(bootstrap_port, &masterPort);
68 if (result != KERN_SUCCESS) {
69 FatalError(-1, "Error (%d) getting the IOMaster port", result);
70 exit(-1);
71 }
72
73 gOptionsRef = IORegistryEntryFromPath(masterPort, "IODeviceTree:/options");
74 if (gOptionsRef == 0) {
09fd88e4 75 FatalError(-1, "nvram is not supported on this system.", -1);
1815bff5
A
76 exit(-1);
77 }
78
79 for (cnt = 1; cnt < argc; cnt++) {
80 str = argv[cnt];
81 if (str[0] == '-' && str[1] != 0) {
82 // Parse the options.
83 for (str += 1 ; *str; str++) {
84 switch (*str) {
85 case 'p' :
86 PrintOFVariables();
87 break;
34d340d7
A
88
89 case 'x' :
90 gUseXML = true;
91 break;
92
1815bff5
A
93 case 'f':
94 cnt++;
95 if (cnt < argc && *argv[cnt] != '-') {
96 ParseFile(argv[cnt]);
97 } else {
98 UsageMessage("missing filename");
99 }
100 break;
101
83f6dbe8
A
102 case 'd':
103 cnt++;
104 if (cnt < argc && *argv[cnt] != '-') {
105 DeleteOFVariable(argv[cnt]);
106 } else {
107 UsageMessage("missing name");
108 }
109 break;
110
34d340d7
A
111 case 'c':
112 ClearOFVariables();
113 break;
114
1815bff5
A
115 default:
116 strcpy(errorMessage, "no such option as --");
117 errorMessage[strlen(errorMessage)-1] = *str;
118 UsageMessage(errorMessage);
119 }
120 }
121 } else {
4c00c0ae 122 // Other arguments will be firmware variable requests.
1815bff5
A
123 SetOrGetOFVariable(str);
124 }
125 }
126
127 IOObjectRelease(gOptionsRef);
128
129 return 0;
130}
131
132
133// Error(format, item)
134//
135// Print a message on standard error.
136//
137static void Error(char *format, long item)
138{
139 fprintf(stderr, "%s: ", gToolName);
140 fprintf(stderr, format, item);
141 fprintf(stderr, "\n");
142}
143
144
145// FatalError(exitValue, format, item)
146//
147// Print a message on standard error and exit with value.
148//
149static void FatalError(long exitValue, char *format, long item)
150{
151 fprintf(stderr, "%s: ", gToolName);
152 fprintf(stderr, format, item);
153 fprintf(stderr, "\n");
154
155 exit(exitValue);
156}
157
158
159// UsageMessage(message)
160//
161// Print the usage information and exit.
162//
163static void UsageMessage(char *message)
164{
165 Error("(usage: %s)", (long)message);
166
34d340d7
A
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");
4c00c0ae
A
170 printf("\t-p print all firmware variables\n");
171 printf("\t-f set firmware variables from a text file\n");
83f6dbe8 172 printf("\t-d delete the named variable\n");
34d340d7 173 printf("\t-c delete all variables\n");
1815bff5
A
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");
177
178 exit(1);
179}
180
181
182// States for ParseFile.
183enum {
184 kFirstColumn = 0,
185 kScanComment,
186 kFindName,
187 kCollectName,
188 kFindValue,
189 kCollectValue,
190 kContinueValue,
191 kSetenv,
192
193 kMaxStringSize = 0x800,
194 kMaxNameSize = 0x100
195};
196
197
198// ParseFile(fileName)
199//
200// Open and parse the specified file.
201//
202static void ParseFile(char *fileName)
203{
204 long state, tc, ni = 0, vi = 0;
205 char name[kMaxNameSize];
206 char value[kMaxStringSize];
207 FILE *patches;
34d340d7
A
208
209 if (gUseXML) {
210 ParseXMLFile(fileName);
211 return;
212 }
1815bff5
A
213
214 patches = fopen(fileName, "r");
215 if (patches == 0) {
216 FatalError(errno, "Couldn't open patch file - '%s'", (long)fileName);
217 }
218
219 state = kFirstColumn;
220 while ((tc = getc(patches)) != EOF) {
34d340d7
A
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);
1815bff5
A
225 switch (state) {
226 case kFirstColumn :
227 ni = 0;
228 vi = 0;
229 if (tc == '#') {
230 state = kScanComment;
231 } else if (tc == '\n') {
232 // state stays kFirstColumn.
233 } else if (isspace(tc)) {
234 state = kFindName;
235 } else {
236 state = kCollectName;
237 name[ni++] = tc;
238 }
239 break;
240
241 case kScanComment :
242 if (tc == '\n') {
243 state = kFirstColumn;
244 } else {
245 // state stays kScanComment.
246 }
247 break;
248
249 case kFindName :
250 if (tc == '\n') {
251 state = kFirstColumn;
252 } else if (isspace(tc)) {
253 // state stays kFindName.
254 } else {
255 state = kCollectName;
256 name[ni++] = tc;
257 }
258 break;
259
260 case kCollectName :
261 if (tc == '\n') {
262 name[ni] = 0;
263 Error("Name must be followed by white space - '%s'", (long)name);
264 state = kFirstColumn;
265 } else if (isspace(tc)) {
266 state = kFindValue;
267 } else {
268 name[ni++] = tc;
269 // state staus kCollectName.
270 }
271 break;
272
273 case kFindValue :
274 case kContinueValue :
275 if (tc == '\n') {
276 state = kSetenv;
277 } else if (isspace(tc)) {
278 // state stays kFindValue or kContinueValue.
279 } else {
280 state = kCollectValue;
281 value[vi++] = tc;
282 }
283 break;
284
285 case kCollectValue :
286 if (tc == '\n') {
287 if (value[vi-1] == '\\') {
288 value[vi-1] = '\r';
289 state = kContinueValue;
290 } else {
291 state = kSetenv;
292 }
293 } else {
294 // state stays kCollectValue.
295 value[vi++] = tc;
296 }
297 break;
298 }
299
300 if (state == kSetenv) {
301 name[ni] = 0;
302 value[vi] = 0;
303 if (SetOFVariable(name, value) != KERN_SUCCESS) {
304 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name);
305 }
306 state = kFirstColumn;
307 }
308 }
309
310 if (state != kFirstColumn) {
311 FatalError(-1, "Last line ended abruptly", 0);
312 }
313}
314
315
34d340d7
A
316// ParseXMLFile(fileName)
317//
318// Open and parse the specified file in XML format,
319// and set variables appropriately.
320//
321static void ParseXMLFile(char *fileName)
322{
323 CFPropertyListRef plist;
324 CFURLRef fileURL = NULL;
325 CFStringRef filePath = NULL;
326 CFStringRef errorString = NULL;
327 CFDataRef data = NULL;
328 SInt32 errorCode = 0;
329
330 filePath = CFStringCreateWithCString(kCFAllocatorDefault, fileName, kCFStringEncodingUTF8);
331 if (filePath == NULL) {
332 FatalError(-1, "Could not create file path string", 0);
333 }
334
335 // Create a URL that specifies the file we will create to
336 // hold the XML data.
337 fileURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault,
338 filePath,
339 kCFURLPOSIXPathStyle,
340 false /* not a directory */ );
341 if (fileURL == NULL) {
342 FatalError(-1, "Could not create file path URL", 0);
343 }
344
345 CFRelease(filePath);
346
347 if (! CFURLCreateDataAndPropertiesFromResource(
348 kCFAllocatorDefault,
349 fileURL,
350 &data,
351 NULL,
352 NULL,
353 &errorCode) || data == NULL ) {
354 FatalError(-1, "Error reading XML file (%d)", errorCode);
355 }
356
357 CFRelease(fileURL);
358
359 plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
360 data,
361 kCFPropertyListImmutable,
362 &errorString);
363
364 CFRelease(data);
365
366 if (plist == NULL) {
367 FatalError(-1, "Error parsing XML file", 0);
368 }
369
370 if (errorString != NULL) {
371 FatalError(-1, "Error parsing XML file: %s", (long)CFStringGetCStringPtr(errorString, kCFStringEncodingUTF8));
372 }
373
374 CFDictionaryApplyFunction(plist, &SetOFVariableFromFile, 0);
375
376 CFRelease(plist);
377}
378
1815bff5
A
379// SetOrGetOFVariable(str)
380//
2fc1e207 381// Parse the input string, then set or get the specified
4c00c0ae 382// firmware variable.
1815bff5
A
383//
384static void SetOrGetOFVariable(char *str)
385{
386 long set = 0;
387 char *name;
388 char *value;
389 CFStringRef nameRef;
390 CFTypeRef valueRef;
391 kern_return_t result;
392
393 // OF variable name is first.
394 name = str;
395
396 // Find the equal sign for set
397 while (*str) {
398 if (*str == '=') {
399 set = 1;
400 *str++ = '\0';
401 break;
402 }
403 str++;
404 }
405
406 if (set == 1) {
407 // On sets, the OF variable's value follows the equal sign.
408 value = str;
409
410 result = SetOFVariable(name, value);
411 if (result != KERN_SUCCESS) {
412 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name);
413 }
414 } else {
415 result = GetOFVariable(name, &nameRef, &valueRef);
416 if (result != KERN_SUCCESS) {
417 FatalError(-1, "Error (-1) getting variable - '%s'", (long)name);
418 }
419
420 PrintOFVariable(nameRef, valueRef, 0);
421 CFRelease(nameRef);
422 CFRelease(valueRef);
423 }
424}
425
426
427// GetOFVariable(name, nameRef, valueRef)
428//
4c00c0ae 429// Get the named firmware variable.
1815bff5
A
430// Return it and it's symbol in valueRef and nameRef.
431//
432static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
433 CFTypeRef *valueRef)
434{
435 *nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
2fc1e207 436 kCFStringEncodingUTF8);
1815bff5 437 if (*nameRef == 0) {
2fc1e207 438 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name);
1815bff5
A
439 }
440
441 *valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, *nameRef, 0, 0);
442 if (*valueRef == 0) return -1;
443
444 return KERN_SUCCESS;
445}
446
447
448// SetOFVariable(name, value)
449//
4c00c0ae 450// Set or create an firmware variable with name and value.
1815bff5
A
451//
452static kern_return_t SetOFVariable(char *name, char *value)
453{
454 CFStringRef nameRef;
455 CFTypeRef valueRef;
456 CFTypeID typeID;
457 kern_return_t result;
458
459 nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
2fc1e207 460 kCFStringEncodingUTF8);
1815bff5
A
461 if (nameRef == 0) {
462 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name);
463 }
464
465 valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, nameRef, 0, 0);
466 if (valueRef) {
467 typeID = CFGetTypeID(valueRef);
468 CFRelease(valueRef);
20e66415
A
469
470 valueRef = ConvertValueToCFTypeRef(typeID, value);
471 if (valueRef == 0) {
472 FatalError(-1, "Error (-1) creating CFTypeRef for value %s",(long)value);
473 } result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
474 } else {
475 while (1) {
476 // In the default case, try data, string, number, then boolean.
477
478 valueRef = ConvertValueToCFTypeRef(CFDataGetTypeID(), value);
479 if (valueRef != 0) {
480 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
481 if (result == KERN_SUCCESS) break;
482 }
483
484 valueRef = ConvertValueToCFTypeRef(CFStringGetTypeID(), value);
485 if (valueRef != 0) {
486 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
487 if (result == KERN_SUCCESS) break;
488 }
489
490 valueRef = ConvertValueToCFTypeRef(CFNumberGetTypeID(), value);
491 if (valueRef != 0) {
492 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
493 if (result == KERN_SUCCESS) break;
494 }
495
496 valueRef = ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value);
497 if (valueRef != 0) {
498 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
499 if (result == KERN_SUCCESS) break;
500 }
501
502 result = -1;
503 break;
504 }
1815bff5
A
505 }
506
1815bff5
A
507 CFRelease(nameRef);
508
509 return result;
510}
511
512
83f6dbe8
A
513// DeleteOFVariable(name)
514//
4c00c0ae 515// Delete the named firmware variable.
83f6dbe8
A
516//
517//
518static void DeleteOFVariable(char *name)
519{
520 SetOFVariable(kIONVRAMDeletePropertyKey, name);
521}
522
523
1815bff5
A
524// PrintOFVariables()
525//
4c00c0ae 526// Print all of the firmware variables.
1815bff5
A
527//
528static void PrintOFVariables()
529{
530 kern_return_t result;
531 CFMutableDictionaryRef dict;
532
533 result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
534 if (result != KERN_SUCCESS) {
4c00c0ae 535 FatalError(-1, "Error (%d) getting the firmware variables", result);
1815bff5 536 }
34d340d7
A
537
538 if (gUseXML) {
539 CFDataRef data;
540
541 data = CFPropertyListCreateXMLData( kCFAllocatorDefault, dict );
542 if (data == NULL) {
543 FatalError(-1, "Error (%d) converting variables to xml", result);
544 }
545
546 fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout);
547
548 CFRelease(data);
549
550 } else {
551
552 CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
553
554 }
1815bff5
A
555
556 CFRelease(dict);
557}
558
1815bff5
A
559// PrintOFVariable(key, value, context)
560//
4c00c0ae 561// Print the given firmware variable.
1815bff5
A
562//
563static void PrintOFVariable(const void *key, const void *value, void *context)
564{
565 long cnt, cnt2;
2fc1e207
A
566 CFIndex nameLen;
567 char *nameBuffer = 0;
1815bff5
A
568 const char *nameString;
569 char numberBuffer[10];
b51d5b5f
A
570 const uint8_t *dataPtr;
571 uint8_t dataChar;
1815bff5 572 char *dataBuffer = 0;
2fc1e207
A
573 CFIndex valueLen;
574 char *valueBuffer = 0;
b51d5b5f
A
575 const char *valueString = 0;
576 uint32_t number, length;
1815bff5
A
577 CFTypeID typeID;
578
579 // Get the OF variable's name.
2fc1e207
A
580 nameLen = CFStringGetLength(key) + 1;
581 nameBuffer = malloc(nameLen);
582 if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
583 nameString = nameBuffer;
584 else {
585 Error("Error (-1) Unable to convert property name to C string", 0);
586 nameString = "<UNPRINTABLE>";
587 }
1815bff5
A
588
589 // Get the OF variable's type.
590 typeID = CFGetTypeID(value);
591
2fc1e207 592 if (typeID == CFBooleanGetTypeID()) {
1815bff5
A
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()) {
2fc1e207
A
602 valueLen = CFStringGetLength(value) + 1;
603 valueBuffer = malloc(valueLen + 1);
604 if ( valueBuffer && CFStringGetCString(value, valueBuffer, valueLen, kCFStringEncodingUTF8) )
605 valueString = valueBuffer;
606 else {
607 Error("Error (-1) Unable to convert value to C string", 0);
608 valueString = "<UNPRINTABLE>";
609 }
1815bff5
A
610 } else if (typeID == CFDataGetTypeID()) {
611 length = CFDataGetLength(value);
612 if (length == 0) valueString = "";
613 else {
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;
620 else {
621 sprintf(dataBuffer + cnt2, "%%%02x", dataChar);
622 cnt2 += 3;
623 }
624 }
625 dataBuffer[cnt2] = '\0';
626 valueString = dataBuffer;
627 }
628 }
2fc1e207
A
629 } else {
630 valueString="<INVALID>";
631 }
1815bff5
A
632
633 if ((nameString != 0) && (valueString != 0))
634 printf("%s\t%s\n", nameString, valueString);
635
636 if (dataBuffer != 0) free(dataBuffer);
2fc1e207
A
637 if (nameBuffer != 0) free(nameBuffer);
638 if (valueBuffer != 0) free(valueBuffer);
1815bff5
A
639}
640
34d340d7
A
641// ClearOFVariables()
642//
643// Deletes all OF variables
644//
645static void ClearOFVariables(void)
646{
647 kern_return_t result;
648 CFMutableDictionaryRef dict;
649
650 result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
651 if (result != KERN_SUCCESS) {
652 FatalError(-1, "Error (%d) getting the firmware variables", result);
653 }
654 CFDictionaryApplyFunction(dict, &ClearOFVariable, 0);
655
656 CFRelease(dict);
657}
658
659static void ClearOFVariable(const void *key, const void *value, void *context)
660{
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);
666 }
667}
1815bff5
A
668
669// ConvertValueToCFTypeRef(typeID, value)
670//
671// Convert the value into a CFType given the typeID.
672//
673static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value)
674{
675 CFTypeRef valueRef = 0;
676 long cnt, cnt2, length;
677 unsigned long number, tmp;
678
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,
685 &number);
686 } else if (typeID == CFStringGetTypeID()) {
687 valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value,
2fc1e207 688 kCFStringEncodingUTF8);
1815bff5
A
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];
702 }
34d340d7 703 valueRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)value,
1815bff5
A
704 cnt2, kCFAllocatorDefault);
705 } else return 0;
706
707 return valueRef;
708}
09fd88e4 709
34d340d7
A
710static void SetOFVariableFromFile(const void *key, const void *value, void *context)
711{
712 kern_return_t result;
713
714 result = IORegistryEntrySetCFProperty(gOptionsRef, key, value);
715 if ( result != KERN_SUCCESS ) {
716 int nameLen;
717 char *nameBuffer;
718 char *nameString;
719
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;
725 else {
726 Error("Error (-1) Unable to convert property name to C string", 0);
727 nameString = "<UNPRINTABLE>";
728 }
729 FatalError(-1, "Error (-1) setting variable - '%s'", (long)nameString);
730 }
731}