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