]> git.saurik.com Git - apple/system_cmds.git/blob - nvram.tproj/nvram.c
20d1927cfedefd90e0f24ba380ae4cbb394c3284
[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 // 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 #if TARGET_OS_BRIDGE
225 printf("\t-m set nvram variables on macOS from bridgeOS\n");
226 #endif
227 printf("\tname=value set named variable\n");
228 printf("\tname print variable\n");
229 printf("Note that arguments and options are executed in order.\n");
230
231 exit(1);
232 }
233
234
235 // States for ParseFile.
236 enum {
237 kFirstColumn = 0,
238 kScanComment,
239 kFindName,
240 kCollectName,
241 kFindValue,
242 kCollectValue,
243 kContinueValue,
244 kSetenv,
245
246 kMaxStringSize = 0x800,
247 kMaxNameSize = 0x100
248 };
249
250
251 // ParseFile(fileName)
252 //
253 // Open and parse the specified file.
254 //
255 static void ParseFile(char *fileName)
256 {
257 long state, ni = 0, vi = 0;
258 int tc;
259 char name[kMaxNameSize];
260 char value[kMaxStringSize];
261 FILE *patches;
262 kern_return_t kret;
263
264 if (gUseXML) {
265 ParseXMLFile(fileName);
266 return;
267 }
268
269 patches = fopen(fileName, "r");
270 if (patches == 0) {
271 err(1, "Couldn't open patch file - '%s'", fileName);
272 }
273
274 state = kFirstColumn;
275 while ((tc = getc(patches)) != EOF) {
276 if(ni==(kMaxNameSize-1))
277 errx(1, "Name exceeded max length of %d", kMaxNameSize);
278 if(vi==(kMaxStringSize-1))
279 errx(1, "Value exceeded max length of %d", kMaxStringSize);
280 switch (state) {
281 case kFirstColumn :
282 ni = 0;
283 vi = 0;
284 if (tc == '#') {
285 state = kScanComment;
286 } else if (tc == '\n') {
287 // state stays kFirstColumn.
288 } else if (isspace(tc)) {
289 state = kFindName;
290 } else {
291 state = kCollectName;
292 name[ni++] = tc;
293 }
294 break;
295
296 case kScanComment :
297 if (tc == '\n') {
298 state = kFirstColumn;
299 } else {
300 // state stays kScanComment.
301 }
302 break;
303
304 case kFindName :
305 if (tc == '\n') {
306 state = kFirstColumn;
307 } else if (isspace(tc)) {
308 // state stays kFindName.
309 } else {
310 state = kCollectName;
311 name[ni++] = tc;
312 }
313 break;
314
315 case kCollectName :
316 if (tc == '\n') {
317 name[ni] = 0;
318 warnx("Name must be followed by white space - '%s'", name);
319 state = kFirstColumn;
320 } else if (isspace(tc)) {
321 state = kFindValue;
322 } else {
323 name[ni++] = tc;
324 // state staus kCollectName.
325 }
326 break;
327
328 case kFindValue :
329 case kContinueValue :
330 if (tc == '\n') {
331 state = kSetenv;
332 } else if (isspace(tc)) {
333 // state stays kFindValue or kContinueValue.
334 } else {
335 state = kCollectValue;
336 value[vi++] = tc;
337 }
338 break;
339
340 case kCollectValue :
341 if (tc == '\n') {
342 if (value[vi-1] == '\\') {
343 value[vi-1] = '\r';
344 state = kContinueValue;
345 } else {
346 state = kSetenv;
347 }
348 } else {
349 // state stays kCollectValue.
350 value[vi++] = tc;
351 }
352 break;
353 }
354
355 if (state == kSetenv) {
356 name[ni] = 0;
357 value[vi] = 0;
358 if ((kret = SetOFVariable(name, value)) != KERN_SUCCESS) {
359 errx(1, "Error setting variable - '%s': %s", name,
360 mach_error_string(kret));
361 }
362 state = kFirstColumn;
363 }
364 }
365
366 if (state != kFirstColumn) {
367 errx(1, "Last line ended abruptly");
368 }
369 }
370
371 // ParseXMLFile(fileName)
372 //
373 // Open and parse the specified file in XML format,
374 // and set variables appropriately.
375 //
376 static void ParseXMLFile(char *fileName)
377 {
378 CFPropertyListRef plist;
379 int fd;
380 struct stat sb;
381 char *buffer;
382 CFReadStreamRef stream;
383 CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0;
384
385 fd = open(fileName, O_RDONLY | O_NOFOLLOW, S_IFREG);
386 if (fd == -1) {
387 errx(1, "Could not open %s: %s", fileName, strerror(errno));
388 }
389
390 if (fstat(fd, &sb) == -1) {
391 errx(1, "Could not fstat %s: %s", fileName, strerror(errno));
392 }
393
394 if (sb.st_size > UINT32_MAX) {
395 errx(1, "too big for our purposes");
396 }
397
398 buffer = malloc((size_t)sb.st_size);
399 if (buffer == NULL) {
400 errx(1, "Could not allocate buffer");
401 }
402
403 if (read(fd, buffer, (size_t)sb.st_size) != sb.st_size) {
404 errx(1, "Could not read %s: %s", fileName, strerror(errno));
405 }
406
407 close(fd);
408
409 stream = CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault,
410 (const UInt8 *)buffer,
411 (CFIndex)sb.st_size,
412 kCFAllocatorNull);
413 if (stream == NULL) {
414 errx(1, "Could not create stream from serialized data");
415 }
416
417 if (!CFReadStreamOpen(stream)) {
418 errx(1, "Could not open the stream");
419 }
420
421 plist = CFPropertyListCreateWithStream(kCFAllocatorDefault,
422 stream,
423 (CFIndex)sb.st_size,
424 kCFPropertyListImmutable,
425 &format,
426 NULL);
427
428 if (plist == NULL) {
429 errx(1, "Error parsing XML file");
430 }
431
432 CFReadStreamClose(stream);
433
434 CFRelease(stream);
435
436 free(buffer);
437
438 CFDictionaryApplyFunction(plist, &SetOFVariableFromFile, 0);
439
440 CFRelease(plist);
441 }
442
443 // SetOrGetOFVariable(str)
444 //
445 // Parse the input string, then set, append or get
446 // the specified firmware variable.
447 //
448 static void SetOrGetOFVariable(char *str)
449 {
450 long set = 0;
451 long append = 0;
452 char *name;
453 char *value;
454 CFStringRef nameRef = NULL;
455 CFTypeRef valueRef = NULL;
456 CFMutableStringRef appended = NULL;
457 kern_return_t result;
458
459 // OF variable name is first.
460 name = str;
461
462 // Find the equal sign for set or += for append
463 while (*str) {
464 if (*str == '+' && *(str+1) == '=') {
465 append = 1;
466 *str++ = '\0';
467 *str++ = '\0';
468 break;
469 }
470
471 if (*str == '=') {
472 set = 1;
473 *str++ = '\0';
474 break;
475 }
476 str++;
477 }
478
479 // Read the current value if appending or if no =/+=
480 if (append == 1 || (set == 0 && append == 0)) {
481 #if TARGET_OS_BRIDGE
482 if (gBridgeToIntel) {
483 result = GetMacOFVariable(name, &value);
484 if (result != KERN_SUCCESS) {
485 errx(1, "Error getting variable - '%s': %s", name,
486 mach_error_string(result));
487 }
488 nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingUTF8);
489 valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value, kCFStringEncodingUTF8);
490 free(value);
491 }
492 else
493 #endif
494 {
495 result = GetOFVariable(name, &nameRef, &valueRef);
496 if (result != KERN_SUCCESS) {
497 errx(1, "Error getting variable - '%s': %s", name,
498 mach_error_string(result));
499 }
500 }
501 }
502
503 if (set == 1) {
504 // On sets, the OF variable's value follows the equal sign.
505 value = str;
506 }
507
508 if (append == 1) {
509 // On append, the value to append follows the += substring
510 appended = CFStringCreateMutableCopy(NULL, 0, valueRef);
511 CFStringAppendCString(appended, str, kCFStringEncodingUTF8);
512 value = (char*)CFStringGetCStringPtr(appended, kCFStringEncodingUTF8);
513 }
514
515 if (set == 1 || append == 1) {
516 #if TARGET_OS_BRIDGE
517 if (gBridgeToIntel) {
518 result = SetMacOFVariable(name, value);
519 }
520 else
521 #endif
522 {
523 result = SetOFVariable(name, value);
524 NVRamSyncNow(name); /* Try syncing the new data to device, best effort! */
525 }
526 if (result != KERN_SUCCESS) {
527 errx(1, "Error setting variable - '%s': %s", name,
528 mach_error_string(result));
529 }
530 } else {
531 PrintOFVariable(nameRef, valueRef, 0);
532 }
533 if ( nameRef ) CFRelease(nameRef);
534 if ( valueRef ) CFRelease(valueRef);
535 if ( appended ) CFRelease(appended);
536 }
537
538 #if TARGET_OS_BRIDGE
539 static kern_return_t LinkMacNVRAMSymbols()
540 {
541 gDL_handle = dlopen("libMacEFIHostInterface.dylib", RTLD_LAZY);
542 if (gDL_handle == NULL) {
543 errx(errno, "Failed to dlopen libMacEFIHostInterface.dylib");
544 return KERN_FAILURE; /* NOTREACHED */
545 }
546
547 hostInterfaceInitialize_fptr = dlsym(gDL_handle, "hostInterfaceInitialize");
548 if (hostInterfaceInitialize_fptr == NULL) {
549 errx(errno, "failed to link hostInterfaceInitialize");
550 }
551 createNvramHostInterface_fptr = dlsym(gDL_handle, "createNvramHostInterface");
552 if (createNvramHostInterface_fptr == NULL) {
553 errx(errno, "failed to link createNvramHostInterface");
554 }
555 destroyNvramHostInterface_fptr = dlsym(gDL_handle, "destroyNvramHostInterface");
556 if (destroyNvramHostInterface_fptr == NULL) {
557 errx(errno, "failed to link destroyNvramHostInterface");
558 }
559 getNVRAMVariable_fptr = dlsym(gDL_handle, "getNVRAMVariable");
560 if (getNVRAMVariable_fptr == NULL) {
561 errx(errno, "failed to link getNVRAMVariable");
562 }
563 setNVRAMVariable_fptr = dlsym(gDL_handle, "setNVRAMVariable");
564 if (setNVRAMVariable_fptr == NULL) {
565 errx(errno, "failed to link setNVRAMVariable");
566 }
567 deleteNVRAMVariable_fptr = dlsym(gDL_handle, "deleteNVRAMVariable");
568 if (deleteNVRAMVariable_fptr == NULL) {
569 errx(errno, "failed to link deleteNVRAMVariable");
570 }
571 hostInterfaceDeinitialize_fptr = dlsym(gDL_handle, "hostInterfaceDeinitialize");
572 if (hostInterfaceDeinitialize_fptr == NULL) {
573 errx(errno, "failed to link hostInterfaceDeinitialize");
574 }
575
576 /* also do the initialization */
577 hostInterfaceInitialize_fptr();
578 gNvramInterface = createNvramHostInterface_fptr(NULL);
579
580 return KERN_SUCCESS;
581 }
582 #endif
583
584 // GetOFVariable(name, nameRef, valueRef)
585 //
586 // Get the named firmware variable.
587 // Return it and it's symbol in valueRef and nameRef.
588 //
589 static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
590 CFTypeRef *valueRef)
591 {
592 *nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
593 kCFStringEncodingUTF8);
594 if (*nameRef == 0) {
595 errx(1, "Error creating CFString for key %s", name);
596 }
597
598 *valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, *nameRef, 0, 0);
599 if (*valueRef == 0) return kIOReturnNotFound;
600
601 return KERN_SUCCESS;
602 }
603
604 #if TARGET_OS_BRIDGE
605 // GetMacOFVariable(name, value)
606 //
607 // Get the named firmware variable from the Intel side.
608 // Return the value in value
609 //
610 static kern_return_t GetMacOFVariable(char *name, char **value)
611 {
612 uint32_t value_size;
613
614 return getNVRAMVariable_fptr(gNvramInterface, name, value, &value_size);
615 }
616 #endif
617
618 // SetOFVariable(name, value)
619 //
620 // Set or create an firmware variable with name and value.
621 //
622 static kern_return_t SetOFVariable(char *name, char *value)
623 {
624 CFStringRef nameRef;
625 CFTypeRef valueRef;
626 CFTypeID typeID;
627 kern_return_t result = KERN_SUCCESS;
628
629 nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
630 kCFStringEncodingUTF8);
631 if (nameRef == 0) {
632 errx(1, "Error creating CFString for key %s", name);
633 }
634
635 valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, nameRef, 0, 0);
636 if (valueRef) {
637 typeID = CFGetTypeID(valueRef);
638 CFRelease(valueRef);
639
640 valueRef = ConvertValueToCFTypeRef(typeID, value);
641 if (valueRef == 0) {
642 errx(1, "Error creating CFTypeRef for value %s", value);
643 } result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
644 } else {
645 while (1) {
646 // In the default case, try data, string, number, then boolean.
647
648 valueRef = ConvertValueToCFTypeRef(CFDataGetTypeID(), value);
649 if (valueRef != 0) {
650 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
651 if (result == KERN_SUCCESS) break;
652 }
653
654 valueRef = ConvertValueToCFTypeRef(CFStringGetTypeID(), value);
655 if (valueRef != 0) {
656 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
657 if (result == KERN_SUCCESS) break;
658 }
659
660 valueRef = ConvertValueToCFTypeRef(CFNumberGetTypeID(), value);
661 if (valueRef != 0) {
662 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
663 if (result == KERN_SUCCESS) break;
664 }
665
666 valueRef = ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value);
667 if (valueRef != 0) {
668 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
669 if (result == KERN_SUCCESS) break;
670 }
671
672 break;
673 }
674 }
675
676 CFRelease(nameRef);
677
678 return result;
679 }
680
681 #if TARGET_OS_BRIDGE
682 static kern_return_t SetMacOFVariable(char *name, char *value)
683 {
684 return setNVRAMVariable_fptr(gNvramInterface, name, value);
685 }
686 #endif
687
688 // DeleteOFVariable(name)
689 //
690 // Delete the named firmware variable.
691 //
692 //
693 static void DeleteOFVariable(char *name)
694 {
695 SetOFVariable(kIONVRAMDeletePropertyKey, name);
696 }
697
698 #if TARGET_OS_BRIDGE
699 static kern_return_t DeleteMacOFVariable(char *name)
700 {
701 return deleteNVRAMVariable_fptr(gNvramInterface, name);
702 }
703 #endif
704
705 static void NVRamSyncNow(char *name)
706 {
707 if (!gUseForceSync) {
708 SetOFVariable(kIONVRAMSyncNowPropertyKey, name);
709 } else {
710 SetOFVariable(kIONVRAMForceSyncNowPropertyKey, name);
711 }
712 }
713
714 // PrintOFVariables()
715 //
716 // Print all of the firmware variables.
717 //
718 static void PrintOFVariables(void)
719 {
720 kern_return_t result;
721 CFMutableDictionaryRef dict;
722
723 result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
724 if (result != KERN_SUCCESS) {
725 errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
726 }
727
728 if (gUseXML) {
729 CFDataRef data;
730
731 data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL );
732 if (data == NULL) {
733 errx(1, "Error converting variables to xml");
734 }
735
736 fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout);
737
738 CFRelease(data);
739
740 } else {
741
742 CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
743
744 }
745
746 CFRelease(dict);
747 }
748
749 // PrintOFVariable(key, value, context)
750 //
751 // Print the given firmware variable.
752 //
753 static void PrintOFVariable(const void *key, const void *value, void *context)
754 {
755 long cnt, cnt2;
756 CFIndex nameLen;
757 char *nameBuffer = 0;
758 const char *nameString;
759 char numberBuffer[10];
760 const uint8_t *dataPtr;
761 uint8_t dataChar;
762 char *dataBuffer = 0;
763 CFIndex valueLen;
764 char *valueBuffer = 0;
765 const char *valueString = 0;
766 uint32_t number;
767 long length;
768 CFTypeID typeID;
769
770 if (gUseXML) {
771 CFDataRef data;
772 CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, &key, &value, 1,
773 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
774 if (dict == NULL) {
775 errx(1, "Error creating dictionary for variable value");
776 }
777
778 data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL );
779 if (data == NULL) {
780 errx(1, "Error creating xml plist for variable");
781 }
782
783 fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout);
784
785 CFRelease(dict);
786 CFRelease(data);
787 return;
788 }
789
790 // Get the OF variable's name.
791 nameLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key),
792 kCFStringEncodingUTF8) + 1;
793 nameBuffer = malloc(nameLen);
794 if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
795 nameString = nameBuffer;
796 else {
797 warnx("Unable to convert property name to C string");
798 nameString = "<UNPRINTABLE>";
799 }
800
801 // Get the OF variable's type.
802 typeID = CFGetTypeID(value);
803
804 if (typeID == CFBooleanGetTypeID()) {
805 if (CFBooleanGetValue(value)) valueString = "true";
806 else valueString = "false";
807 } else if (typeID == CFNumberGetTypeID()) {
808 CFNumberGetValue(value, kCFNumberSInt32Type, &number);
809 if (number == 0xFFFFFFFF) sprintf(numberBuffer, "-1");
810 else if (number < 1000) sprintf(numberBuffer, "%d", number);
811 else sprintf(numberBuffer, "0x%x", number);
812 valueString = numberBuffer;
813 } else if (typeID == CFStringGetTypeID()) {
814 valueLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value),
815 kCFStringEncodingUTF8) + 1;
816 valueBuffer = malloc(valueLen + 1);
817 if ( valueBuffer && CFStringGetCString(value, valueBuffer, valueLen, kCFStringEncodingUTF8) )
818 valueString = valueBuffer;
819 else {
820 warnx("Unable to convert value to C string");
821 valueString = "<UNPRINTABLE>";
822 }
823 } else if (typeID == CFDataGetTypeID()) {
824 length = CFDataGetLength(value);
825 if (length == 0) valueString = "";
826 else {
827 dataBuffer = malloc(length * 3 + 1);
828 if (dataBuffer != 0) {
829 dataPtr = CFDataGetBytePtr(value);
830 for (cnt = cnt2 = 0; cnt < length; cnt++) {
831 dataChar = dataPtr[cnt];
832 if (isprint(dataChar) && dataChar != '%') {
833 dataBuffer[cnt2++] = dataChar;
834 } else {
835 sprintf(dataBuffer + cnt2, "%%%02x", dataChar);
836 cnt2 += 3;
837 }
838 }
839 dataBuffer[cnt2] = '\0';
840 valueString = dataBuffer;
841 }
842 }
843 } else {
844 valueString="<INVALID>";
845 }
846
847 if ((nameString != 0) && (valueString != 0))
848 printf("%s\t%s\n", nameString, valueString);
849
850 if (dataBuffer != 0) free(dataBuffer);
851 if (nameBuffer != 0) free(nameBuffer);
852 if (valueBuffer != 0) free(valueBuffer);
853 }
854
855 // ClearOFVariables()
856 //
857 // Deletes all OF variables
858 //
859 static void ClearOFVariables(void)
860 {
861 kern_return_t result;
862 CFMutableDictionaryRef dict;
863
864 result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
865 if (result != KERN_SUCCESS) {
866 errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
867 }
868 CFDictionaryApplyFunction(dict, &ClearOFVariable, 0);
869
870 CFRelease(dict);
871 }
872
873 static void ClearOFVariable(const void *key, const void *value, void *context)
874 {
875 kern_return_t result;
876 result = IORegistryEntrySetCFProperty(gOptionsRef,
877 CFSTR(kIONVRAMDeletePropertyKey), key);
878 if (result != KERN_SUCCESS) {
879 assert(CFGetTypeID(key) == CFStringGetTypeID());
880 const char *keyStr = CFStringGetCStringPtr(key, kCFStringEncodingUTF8);
881 char *keyBuffer = NULL;
882 size_t keyBufferLen = 0;
883 if (!keyStr) {
884 keyBufferLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key), kCFStringEncodingUTF8) + 1;
885 keyBuffer = (char *)malloc(keyBufferLen);
886 if (keyBuffer != NULL && CFStringGetCString(key, keyBuffer, keyBufferLen, kCFStringEncodingUTF8)) {
887 keyStr = keyBuffer;
888 } else {
889 warnx("Unable to convert property name to C string");
890 keyStr = "<UNPRINTABLE>";
891 }
892 }
893
894 warnx("Error clearing firmware variable %s: %s", keyStr, mach_error_string(result));
895 if (keyBuffer) {
896 free(keyBuffer);
897 }
898 }
899 }
900
901 // ConvertValueToCFTypeRef(typeID, value)
902 //
903 // Convert the value into a CFType given the typeID.
904 //
905 static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value)
906 {
907 CFTypeRef valueRef = 0;
908 long cnt, cnt2, length;
909 unsigned long number, tmp;
910
911 if (typeID == CFBooleanGetTypeID()) {
912 if (!strcmp("true", value)) valueRef = kCFBooleanTrue;
913 else if (!strcmp("false", value)) valueRef = kCFBooleanFalse;
914 } else if (typeID == CFNumberGetTypeID()) {
915 number = strtol(value, 0, 0);
916 valueRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type,
917 &number);
918 } else if (typeID == CFStringGetTypeID()) {
919 valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value,
920 kCFStringEncodingUTF8);
921 } else if (typeID == CFDataGetTypeID()) {
922 length = strlen(value);
923 for (cnt = cnt2 = 0; cnt < length; cnt++, cnt2++) {
924 if (value[cnt] == '%') {
925 if (!ishexnumber(value[cnt + 1]) ||
926 !ishexnumber(value[cnt + 2])) return 0;
927 number = toupper(value[++cnt]) - '0';
928 if (number > 9) number -= 7;
929 tmp = toupper(value[++cnt]) - '0';
930 if (tmp > 9) tmp -= 7;
931 number = (number << 4) + tmp;
932 value[cnt2] = number;
933 } else value[cnt2] = value[cnt];
934 }
935 valueRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)value,
936 cnt2, kCFAllocatorDefault);
937 } else return 0;
938
939 return valueRef;
940 }
941
942 static void SetOFVariableFromFile(const void *key, const void *value, void *context)
943 {
944 kern_return_t result;
945
946 result = IORegistryEntrySetCFProperty(gOptionsRef, key, value);
947 if ( result != KERN_SUCCESS ) {
948 long nameLen;
949 char *nameBuffer;
950 char *nameString;
951
952 // Get the variable's name.
953 nameLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key),
954 kCFStringEncodingUTF8) + 1;
955 nameBuffer = malloc(nameLen);
956 if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
957 nameString = nameBuffer;
958 else {
959 warnx("Unable to convert property name to C string");
960 nameString = "<UNPRINTABLE>";
961 }
962 errx(1, "Error setting variable - '%s': %s", nameString,
963 mach_error_string(result));
964 }
965 }