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