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