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