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