]> git.saurik.com Git - apple/system_cmds.git/blob - nvram.tproj/nvram.c
system_cmds-790.30.1.tar.gz
[apple/system_cmds.git] / nvram.tproj / nvram.c
1 /*
2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
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
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall
24 */
25
26 #include <stdio.h>
27 #include <IOKit/IOKitLib.h>
28 #include <IOKit/IOKitKeys.h>
29 #include <IOKit/IOKitKeysPrivate.h>
30 #include <CoreFoundation/CoreFoundation.h>
31 #include <err.h>
32 #include <mach/mach_error.h>
33 #include <sys/stat.h>
34
35 // Prototypes
36 static void UsageMessage(char *message);
37 static void ParseFile(char *fileName);
38 static void ParseXMLFile(char *fileName);
39 static void SetOrGetOFVariable(char *str);
40 static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
41 CFTypeRef *valueRef);
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 void SetOFVariableFromFile(const void *key, const void *value, void *context);
47 static void ClearOFVariables(void);
48 static void ClearOFVariable(const void *key,const void *value,void *context);
49 static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value);
50
51 static void NVRamSyncNow(char *name);
52
53 // Global Variables
54 static char *gToolName;
55 static io_registry_entry_t gOptionsRef;
56 static bool gUseXML;
57 static bool gUseForceSync;
58
59 #if TARGET_OS_BRIDGE /* Stuff for nvram bridge -> intel */
60 #include <dlfcn.h>
61 #include <libMacEFIManager/MacEFIHostInterfaceAPI.h>
62
63 static kern_return_t LinkMacNVRAMSymbols(void);
64 static kern_return_t GetMacOFVariable(char *name, char **value);
65 static kern_return_t SetMacOFVariable(char *name, char *value);
66 static void DeleteMacOFVariable(char *name);
67
68 static bool gBridgeToIntel;
69 static void *gDL_handle;
70 static void *gNvramInterface;
71
72 static void (*hostInterfaceInitialize_fptr)(void);
73 static void *(*createNvramHostInterface_fptr)(const char *handle);
74 static kern_return_t (*destroyNvramHostInterface_fptr)(void *interface);
75 static kern_return_t (*getNVRAMVariable_fptr)(void *interface, char *name, char **buffer, uint32_t *size);
76 static kern_return_t (*setNVRAMVariable_fptr)(void *interface, char *name, char *buffer, uint32_t size);
77 static void (*hostInterfaceDeinitialize_fptr)(void); /* may not need? */
78
79 #endif /* TARGET_OS_BRIDGE */
80
81 int main(int argc, char **argv)
82 {
83 long cnt;
84 char *str, errorMessage[256];
85 kern_return_t result;
86 mach_port_t masterPort;
87 int argcount = 0;
88
89 // Get the name of the command.
90 gToolName = strrchr(argv[0], '/');
91 if (gToolName != 0) gToolName++;
92 else gToolName = argv[0];
93
94 result = IOMasterPort(bootstrap_port, &masterPort);
95 if (result != KERN_SUCCESS) {
96 errx(1, "Error getting the IOMaster port: %s",
97 mach_error_string(result));
98 }
99
100 gOptionsRef = IORegistryEntryFromPath(masterPort, "IODeviceTree:/options");
101 if (gOptionsRef == 0) {
102 errx(1, "nvram is not supported on this system");
103 }
104
105 for (cnt = 1; cnt < argc; cnt++) {
106 str = argv[cnt];
107 if (str[0] == '-' && str[1] != 0) {
108 // Parse the options.
109 for (str += 1 ; *str; str++) {
110 switch (*str) {
111 case 'p' :
112 #if TARGET_OS_BRIDGE
113 if (gBridgeToIntel) {
114 fprintf(stderr, "-p not supported for Mac NVRAM store.\n");
115 return 1;
116 }
117 #endif
118 PrintOFVariables();
119 break;
120
121 case 'x' :
122 gUseXML = true;
123 break;
124
125 case 'f':
126 #if TARGET_OS_BRIDGE
127 if (gBridgeToIntel) {
128 fprintf(stderr, "-f not supported for Mac NVRAM store.\n");
129 return 1;
130 }
131 #endif
132 cnt++;
133 if (cnt < argc && *argv[cnt] != '-') {
134 ParseFile(argv[cnt]);
135 } else {
136 UsageMessage("missing filename");
137 }
138 break;
139
140 case 'd':
141 #if TARGET_OS_BRIDGE
142 if (gBridgeToIntel) {
143 fprintf(stderr, "-d not supported for Mac NVRAM store.\n");
144 return 1;
145 }
146 #endif
147 cnt++;
148 if (cnt < argc && *argv[cnt] != '-') {
149 DeleteOFVariable(argv[cnt]);
150 } else {
151 UsageMessage("missing name");
152 }
153 break;
154
155 case 'c':
156 #if TARGET_OS_BRIDGE
157 if (gBridgeToIntel) {
158 fprintf(stderr, "-c not supported for Mac NVRAM store.\n");
159 return 1;
160 }
161 #endif
162 ClearOFVariables();
163 break;
164 case 's':
165 // -s option is unadvertised -- advises the kernel more forcibly to
166 // commit the variable to nonvolatile storage
167 gUseForceSync = true;
168 break;
169 #if TARGET_OS_BRIDGE
170 case 'm':
171 // -m option is unadvertised -- used to set nvram variables on the Intel side
172 // from the ARM side (Bridge -> Mac)
173 fprintf(stdout, "Using Mac NVRAM store.\n");
174
175 LinkMacNVRAMSymbols();
176 gBridgeToIntel = true;
177 break;
178 #endif
179
180 default:
181 strcpy(errorMessage, "no such option as --");
182 errorMessage[strlen(errorMessage)-1] = *str;
183 UsageMessage(errorMessage);
184 }
185 }
186 } else {
187 // Other arguments will be firmware variable requests.
188 argcount++;
189 SetOrGetOFVariable(str);
190 }
191 }
192
193 // radar:25206371
194 if (argcount == 0 && gUseForceSync == true) {
195 NVRamSyncNow("");
196 }
197
198 IOObjectRelease(gOptionsRef);
199
200 return 0;
201 }
202
203 // UsageMessage(message)
204 //
205 // Print the usage information and exit.
206 //
207 static void UsageMessage(char *message)
208 {
209 warnx("(usage: %s)", message);
210
211 printf("%s [-x] [-p] [-f filename] [-d name] [-c] name[=value] ...\n", gToolName);
212 printf("\t-x use XML format for printing or reading variables\n");
213 printf("\t (must appear before -p or -f)\n");
214 printf("\t-p print all firmware variables\n");
215 printf("\t-f set firmware variables from a text file\n");
216 printf("\t-d delete the named variable\n");
217 printf("\t-c delete all variables\n");
218 printf("\tname=value set named variable\n");
219 printf("\tname print variable\n");
220 printf("Note that arguments and options are executed in order.\n");
221
222 exit(1);
223 }
224
225
226 // States for ParseFile.
227 enum {
228 kFirstColumn = 0,
229 kScanComment,
230 kFindName,
231 kCollectName,
232 kFindValue,
233 kCollectValue,
234 kContinueValue,
235 kSetenv,
236
237 kMaxStringSize = 0x800,
238 kMaxNameSize = 0x100
239 };
240
241
242 // ParseFile(fileName)
243 //
244 // Open and parse the specified file.
245 //
246 static void ParseFile(char *fileName)
247 {
248 long state, ni = 0, vi = 0;
249 int tc;
250 char name[kMaxNameSize];
251 char value[kMaxStringSize];
252 FILE *patches;
253 kern_return_t kret;
254
255 if (gUseXML) {
256 ParseXMLFile(fileName);
257 return;
258 }
259
260 patches = fopen(fileName, "r");
261 if (patches == 0) {
262 err(1, "Couldn't open patch file - '%s'", fileName);
263 }
264
265 state = kFirstColumn;
266 while ((tc = getc(patches)) != EOF) {
267 if(ni==(kMaxNameSize-1))
268 errx(1, "Name exceeded max length of %d", kMaxNameSize);
269 if(vi==(kMaxStringSize-1))
270 errx(1, "Value exceeded max length of %d", kMaxStringSize);
271 switch (state) {
272 case kFirstColumn :
273 ni = 0;
274 vi = 0;
275 if (tc == '#') {
276 state = kScanComment;
277 } else if (tc == '\n') {
278 // state stays kFirstColumn.
279 } else if (isspace(tc)) {
280 state = kFindName;
281 } else {
282 state = kCollectName;
283 name[ni++] = tc;
284 }
285 break;
286
287 case kScanComment :
288 if (tc == '\n') {
289 state = kFirstColumn;
290 } else {
291 // state stays kScanComment.
292 }
293 break;
294
295 case kFindName :
296 if (tc == '\n') {
297 state = kFirstColumn;
298 } else if (isspace(tc)) {
299 // state stays kFindName.
300 } else {
301 state = kCollectName;
302 name[ni++] = tc;
303 }
304 break;
305
306 case kCollectName :
307 if (tc == '\n') {
308 name[ni] = 0;
309 warnx("Name must be followed by white space - '%s'", name);
310 state = kFirstColumn;
311 } else if (isspace(tc)) {
312 state = kFindValue;
313 } else {
314 name[ni++] = tc;
315 // state staus kCollectName.
316 }
317 break;
318
319 case kFindValue :
320 case kContinueValue :
321 if (tc == '\n') {
322 state = kSetenv;
323 } else if (isspace(tc)) {
324 // state stays kFindValue or kContinueValue.
325 } else {
326 state = kCollectValue;
327 value[vi++] = tc;
328 }
329 break;
330
331 case kCollectValue :
332 if (tc == '\n') {
333 if (value[vi-1] == '\\') {
334 value[vi-1] = '\r';
335 state = kContinueValue;
336 } else {
337 state = kSetenv;
338 }
339 } else {
340 // state stays kCollectValue.
341 value[vi++] = tc;
342 }
343 break;
344 }
345
346 if (state == kSetenv) {
347 name[ni] = 0;
348 value[vi] = 0;
349 if ((kret = SetOFVariable(name, value)) != KERN_SUCCESS) {
350 errx(1, "Error setting variable - '%s': %s", name,
351 mach_error_string(kret));
352 }
353 state = kFirstColumn;
354 }
355 }
356
357 if (state != kFirstColumn) {
358 errx(1, "Last line ended abruptly");
359 }
360 }
361
362 // ParseXMLFile(fileName)
363 //
364 // Open and parse the specified file in XML format,
365 // and set variables appropriately.
366 //
367 static void ParseXMLFile(char *fileName)
368 {
369 CFPropertyListRef plist;
370 int fd;
371 struct stat sb;
372 char *buffer;
373 CFReadStreamRef stream;
374 CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0;
375
376 fd = open(fileName, O_RDONLY | O_NOFOLLOW, S_IFREG);
377 if (fd == -1) {
378 errx(1, "Could not open %s: %s", fileName, strerror(errno));
379 }
380
381 if (fstat(fd, &sb) == -1) {
382 errx(1, "Could not fstat %s: %s", fileName, strerror(errno));
383 }
384
385 if (sb.st_size > UINT32_MAX) {
386 errx(1, "too big for our purposes");
387 }
388
389 buffer = malloc((size_t)sb.st_size);
390 if (buffer == NULL) {
391 errx(1, "Could not allocate buffer");
392 }
393
394 if (read(fd, buffer, (size_t)sb.st_size) != sb.st_size) {
395 errx(1, "Could not read %s: %s", fileName, strerror(errno));
396 }
397
398 close(fd);
399
400 stream = CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault,
401 (const UInt8 *)buffer,
402 (CFIndex)sb.st_size,
403 kCFAllocatorNull);
404 if (stream == NULL) {
405 errx(1, "Could not create stream from serialized data");
406 }
407
408 if (!CFReadStreamOpen(stream)) {
409 errx(1, "Could not open the stream");
410 }
411
412 plist = CFPropertyListCreateWithStream(kCFAllocatorDefault,
413 stream,
414 (CFIndex)sb.st_size,
415 kCFPropertyListImmutable,
416 &format,
417 NULL);
418
419 if (plist == NULL) {
420 errx(1, "Error parsing XML file");
421 }
422
423 CFReadStreamClose(stream);
424
425 CFRelease(stream);
426
427 free(buffer);
428
429 CFDictionaryApplyFunction(plist, &SetOFVariableFromFile, 0);
430
431 CFRelease(plist);
432 }
433
434 // SetOrGetOFVariable(str)
435 //
436 // Parse the input string, then set or get the specified
437 // firmware variable.
438 //
439 static void SetOrGetOFVariable(char *str)
440 {
441 long set = 0;
442 char *name;
443 char *value;
444 CFStringRef nameRef;
445 CFTypeRef valueRef;
446 kern_return_t result;
447
448 // OF variable name is first.
449 name = str;
450
451 // Find the equal sign for set
452 while (*str) {
453 if (*str == '=') {
454 set = 1;
455 *str++ = '\0';
456 break;
457 }
458 str++;
459 }
460
461 if (set == 1) {
462 // On sets, the OF variable's value follows the equal sign.
463 value = str;
464 #if TARGET_OS_BRIDGE
465 if (gBridgeToIntel) {
466 result = SetMacOFVariable(name, value);
467 }
468 else
469 #endif
470 {
471 result = SetOFVariable(name, value);
472 NVRamSyncNow(name); /* Try syncing the new data to device, best effort! */
473 }
474 if (result != KERN_SUCCESS) {
475 errx(1, "Error setting variable - '%s': %s", name,
476 mach_error_string(result));
477 }
478 } else {
479 #if TARGET_OS_BRIDGE
480 if (gBridgeToIntel) {
481 result = GetMacOFVariable(name, &value);
482 if (result != KERN_SUCCESS) {
483 errx(1, "Error getting variable - '%s': %s", name,
484 mach_error_string(result));
485 }
486 nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingUTF8);
487 valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value, kCFStringEncodingUTF8);
488 }
489 else
490 #endif
491 {
492 result = GetOFVariable(name, &nameRef, &valueRef);
493 if (result != KERN_SUCCESS) {
494 errx(1, "Error getting variable - '%s': %s", name,
495 mach_error_string(result));
496 }
497 }
498
499 PrintOFVariable(nameRef, valueRef, 0);
500 CFRelease(nameRef);
501 CFRelease(valueRef);
502 }
503 }
504
505 #if TARGET_OS_BRIDGE
506 static kern_return_t LinkMacNVRAMSymbols()
507 {
508 gDL_handle = dlopen("libMacEFIHostInterface.dylib", RTLD_LAZY);
509 if (gDL_handle == NULL) {
510 errx(errno, "Failed to dlopen libMacEFIHostInterface.dylib");
511 return KERN_FAILURE; /* NOTREACHED */
512 }
513
514 hostInterfaceInitialize_fptr = dlsym(gDL_handle, "hostInterfaceInitialize");
515 if (hostInterfaceInitialize_fptr == NULL) {
516 errx(errno, "failed to link hostInterfaceInitialize");
517 }
518 createNvramHostInterface_fptr = dlsym(gDL_handle, "createNvramHostInterface");
519 if (createNvramHostInterface_fptr == NULL) {
520 errx(errno, "failed to link createNvramHostInterface");
521 }
522 destroyNvramHostInterface_fptr = dlsym(gDL_handle, "destroyNvramHostInterface");
523 if (destroyNvramHostInterface_fptr == NULL) {
524 errx(errno, "failed to link destroyNvramHostInterface");
525 }
526 getNVRAMVariable_fptr = dlsym(gDL_handle, "getNVRAMVariable");
527 if (getNVRAMVariable_fptr == NULL) {
528 errx(errno, "failed to link getNVRAMVariable");
529 }
530 setNVRAMVariable_fptr = dlsym(gDL_handle, "setNVRAMVariable");
531 if (setNVRAMVariable_fptr == NULL) {
532 errx(errno, "failed to link setNVRAMVariable");
533 }
534 hostInterfaceDeinitialize_fptr = dlsym(gDL_handle, "hostInterfaceDeinitialize");
535 if (hostInterfaceDeinitialize_fptr == NULL) {
536 errx(errno, "failed to link hostInterfaceDeinitialize");
537 }
538
539 /* also do the initialization */
540 hostInterfaceInitialize_fptr();
541 gNvramInterface = createNvramHostInterface_fptr(NULL);
542
543 return KERN_SUCCESS;
544 }
545 #endif
546
547 // GetOFVariable(name, nameRef, valueRef)
548 //
549 // Get the named firmware variable.
550 // Return it and it's symbol in valueRef and nameRef.
551 //
552 static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
553 CFTypeRef *valueRef)
554 {
555 *nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
556 kCFStringEncodingUTF8);
557 if (*nameRef == 0) {
558 errx(1, "Error creating CFString for key %s", name);
559 }
560
561 *valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, *nameRef, 0, 0);
562 if (*valueRef == 0) return kIOReturnNotFound;
563
564 return KERN_SUCCESS;
565 }
566
567 #if TARGET_OS_BRIDGE
568 // GetMacOFVariable(name, value)
569 //
570 // Get the named firmware variable from the Intel side.
571 // Return the value in value
572 //
573 static kern_return_t GetMacOFVariable(char *name, char **value)
574 {
575 uint32_t value_size;
576 kern_return_t result = KERN_FAILURE;
577 assert(getNVRAMVariable_fptr != NULL);
578
579 result = getNVRAMVariable_fptr(gNvramInterface, name, value, &value_size);
580
581 return result;
582 }
583 #endif
584
585 // SetOFVariable(name, value)
586 //
587 // Set or create an firmware variable with name and value.
588 //
589 static kern_return_t SetOFVariable(char *name, char *value)
590 {
591 CFStringRef nameRef;
592 CFTypeRef valueRef;
593 CFTypeID typeID;
594 kern_return_t result = KERN_SUCCESS;
595
596 nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
597 kCFStringEncodingUTF8);
598 if (nameRef == 0) {
599 errx(1, "Error creating CFString for key %s", name);
600 }
601
602 valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, nameRef, 0, 0);
603 if (valueRef) {
604 typeID = CFGetTypeID(valueRef);
605 CFRelease(valueRef);
606
607 valueRef = ConvertValueToCFTypeRef(typeID, value);
608 if (valueRef == 0) {
609 errx(1, "Error creating CFTypeRef for value %s", value);
610 } result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
611 } else {
612 while (1) {
613 // In the default case, try data, string, number, then boolean.
614
615 valueRef = ConvertValueToCFTypeRef(CFDataGetTypeID(), value);
616 if (valueRef != 0) {
617 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
618 if (result == KERN_SUCCESS) break;
619 }
620
621 valueRef = ConvertValueToCFTypeRef(CFStringGetTypeID(), value);
622 if (valueRef != 0) {
623 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
624 if (result == KERN_SUCCESS) break;
625 }
626
627 valueRef = ConvertValueToCFTypeRef(CFNumberGetTypeID(), value);
628 if (valueRef != 0) {
629 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
630 if (result == KERN_SUCCESS) break;
631 }
632
633 valueRef = ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value);
634 if (valueRef != 0) {
635 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
636 if (result == KERN_SUCCESS) break;
637 }
638
639 break;
640 }
641 }
642
643 CFRelease(nameRef);
644
645 return result;
646 }
647
648 #if TARGET_OS_BRIDGE
649 static kern_return_t SetMacOFVariable(char *name, char *value)
650 {
651 kern_return_t result = KERN_FAILURE;
652 assert(setNVRAMVariable_fptr != NULL);
653
654 result = setNVRAMVariable_fptr(gNvramInterface, name, value, strlen(value));
655
656 return result;
657 }
658 #endif
659
660 // DeleteOFVariable(name)
661 //
662 // Delete the named firmware variable.
663 //
664 //
665 static void DeleteOFVariable(char *name)
666 {
667 SetOFVariable(kIONVRAMDeletePropertyKey, name);
668 }
669
670 #if TARGET_OS_BRIDGE
671 static void DeleteMacOFVariable(char *name)
672 {
673 /* Not yet implementable */
674 }
675 #endif
676
677 static void NVRamSyncNow(char *name)
678 {
679 if (!gUseForceSync) {
680 SetOFVariable(kIONVRAMSyncNowPropertyKey, name);
681 } else {
682 SetOFVariable(kIONVRAMForceSyncNowPropertyKey, name);
683 }
684 }
685
686 // PrintOFVariables()
687 //
688 // Print all of the firmware variables.
689 //
690 static void PrintOFVariables(void)
691 {
692 kern_return_t result;
693 CFMutableDictionaryRef dict;
694
695 result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
696 if (result != KERN_SUCCESS) {
697 errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
698 }
699
700 if (gUseXML) {
701 CFDataRef data;
702
703 data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL );
704 if (data == NULL) {
705 errx(1, "Error converting variables to xml");
706 }
707
708 fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout);
709
710 CFRelease(data);
711
712 } else {
713
714 CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
715
716 }
717
718 CFRelease(dict);
719 }
720
721 // PrintOFVariable(key, value, context)
722 //
723 // Print the given firmware variable.
724 //
725 static void PrintOFVariable(const void *key, const void *value, void *context)
726 {
727 long cnt, cnt2;
728 CFIndex nameLen;
729 char *nameBuffer = 0;
730 const char *nameString;
731 char numberBuffer[10];
732 const uint8_t *dataPtr;
733 uint8_t dataChar;
734 char *dataBuffer = 0;
735 CFIndex valueLen;
736 char *valueBuffer = 0;
737 const char *valueString = 0;
738 uint32_t number;
739 long length;
740 CFTypeID typeID;
741
742 if (gUseXML) {
743 CFDataRef data;
744 CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, &key, &value, 1,
745 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
746 if (dict == NULL) {
747 errx(1, "Error creating dictionary for variable value");
748 }
749
750 data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL );
751 if (data == NULL) {
752 errx(1, "Error creating xml plist for variable");
753 }
754
755 fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout);
756
757 CFRelease(dict);
758 CFRelease(data);
759 return;
760 }
761
762 // Get the OF variable's name.
763 nameLen = CFStringGetLength(key) + 1;
764 nameBuffer = malloc(nameLen);
765 if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
766 nameString = nameBuffer;
767 else {
768 warnx("Unable to convert property name to C string");
769 nameString = "<UNPRINTABLE>";
770 }
771
772 // Get the OF variable's type.
773 typeID = CFGetTypeID(value);
774
775 if (typeID == CFBooleanGetTypeID()) {
776 if (CFBooleanGetValue(value)) valueString = "true";
777 else valueString = "false";
778 } else if (typeID == CFNumberGetTypeID()) {
779 CFNumberGetValue(value, kCFNumberSInt32Type, &number);
780 if (number == 0xFFFFFFFF) sprintf(numberBuffer, "-1");
781 else if (number < 1000) sprintf(numberBuffer, "%d", number);
782 else sprintf(numberBuffer, "0x%x", number);
783 valueString = numberBuffer;
784 } else if (typeID == CFStringGetTypeID()) {
785 valueLen = CFStringGetLength(value) + 1;
786 valueBuffer = malloc(valueLen + 1);
787 if ( valueBuffer && CFStringGetCString(value, valueBuffer, valueLen, kCFStringEncodingUTF8) )
788 valueString = valueBuffer;
789 else {
790 warnx("Unable to convert value to C string");
791 valueString = "<UNPRINTABLE>";
792 }
793 } else if (typeID == CFDataGetTypeID()) {
794 length = CFDataGetLength(value);
795 if (length == 0) valueString = "";
796 else {
797 dataBuffer = malloc(length * 3 + 1);
798 if (dataBuffer != 0) {
799 dataPtr = CFDataGetBytePtr(value);
800 for (cnt = cnt2 = 0; cnt < length; cnt++) {
801 dataChar = dataPtr[cnt];
802 if (isprint(dataChar) && dataChar != '%') {
803 dataBuffer[cnt2++] = dataChar;
804 } else {
805 sprintf(dataBuffer + cnt2, "%%%02x", dataChar);
806 cnt2 += 3;
807 }
808 }
809 dataBuffer[cnt2] = '\0';
810 valueString = dataBuffer;
811 }
812 }
813 } else {
814 valueString="<INVALID>";
815 }
816
817 if ((nameString != 0) && (valueString != 0))
818 printf("%s\t%s\n", nameString, valueString);
819
820 if (dataBuffer != 0) free(dataBuffer);
821 if (nameBuffer != 0) free(nameBuffer);
822 if (valueBuffer != 0) free(valueBuffer);
823 }
824
825 // ClearOFVariables()
826 //
827 // Deletes all OF variables
828 //
829 static void ClearOFVariables(void)
830 {
831 kern_return_t result;
832 CFMutableDictionaryRef dict;
833
834 result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
835 if (result != KERN_SUCCESS) {
836 errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
837 }
838 CFDictionaryApplyFunction(dict, &ClearOFVariable, 0);
839
840 CFRelease(dict);
841 }
842
843 static void ClearOFVariable(const void *key, const void *value, void *context)
844 {
845 kern_return_t result;
846 result = IORegistryEntrySetCFProperty(gOptionsRef,
847 CFSTR(kIONVRAMDeletePropertyKey), key);
848 if (result != KERN_SUCCESS) {
849 errx(1, "Error clearing firmware variables: %s", mach_error_string(result));
850 }
851 }
852
853 // ConvertValueToCFTypeRef(typeID, value)
854 //
855 // Convert the value into a CFType given the typeID.
856 //
857 static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value)
858 {
859 CFTypeRef valueRef = 0;
860 long cnt, cnt2, length;
861 unsigned long number, tmp;
862
863 if (typeID == CFBooleanGetTypeID()) {
864 if (!strcmp("true", value)) valueRef = kCFBooleanTrue;
865 else if (!strcmp("false", value)) valueRef = kCFBooleanFalse;
866 } else if (typeID == CFNumberGetTypeID()) {
867 number = strtol(value, 0, 0);
868 valueRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type,
869 &number);
870 } else if (typeID == CFStringGetTypeID()) {
871 valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value,
872 kCFStringEncodingUTF8);
873 } else if (typeID == CFDataGetTypeID()) {
874 length = strlen(value);
875 for (cnt = cnt2 = 0; cnt < length; cnt++, cnt2++) {
876 if (value[cnt] == '%') {
877 if (!ishexnumber(value[cnt + 1]) ||
878 !ishexnumber(value[cnt + 2])) return 0;
879 number = toupper(value[++cnt]) - '0';
880 if (number > 9) number -= 7;
881 tmp = toupper(value[++cnt]) - '0';
882 if (tmp > 9) tmp -= 7;
883 number = (number << 4) + tmp;
884 value[cnt2] = number;
885 } else value[cnt2] = value[cnt];
886 }
887 valueRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)value,
888 cnt2, kCFAllocatorDefault);
889 } else return 0;
890
891 return valueRef;
892 }
893
894 static void SetOFVariableFromFile(const void *key, const void *value, void *context)
895 {
896 kern_return_t result;
897
898 result = IORegistryEntrySetCFProperty(gOptionsRef, key, value);
899 if ( result != KERN_SUCCESS ) {
900 long nameLen;
901 char *nameBuffer;
902 char *nameString;
903
904 // Get the variable's name.
905 nameLen = CFStringGetLength(key) + 1;
906 nameBuffer = malloc(nameLen);
907 if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
908 nameString = nameBuffer;
909 else {
910 warnx("Unable to convert property name to C string");
911 nameString = "<UNPRINTABLE>";
912 }
913 errx(1, "Error setting variable - '%s': %s", nameString,
914 mach_error_string(result));
915 }
916 }