]>
Commit | Line | Data |
---|---|---|
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 | 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> |
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 |
36 | static void UsageMessage(char *message); |
37 | static void ParseFile(char *fileName); | |
34d340d7 | 38 | static void ParseXMLFile(char *fileName); |
1815bff5 A |
39 | static void SetOrGetOFVariable(char *str); |
40 | static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef, | |
41 | CFTypeRef *valueRef); | |
42 | static kern_return_t SetOFVariable(char *name, char *value); | |
83f6dbe8 | 43 | static void DeleteOFVariable(char *name); |
1815bff5 A |
44 | static void PrintOFVariables(void); |
45 | static void PrintOFVariable(const void *key,const void *value,void *context); | |
34d340d7 A |
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); | |
1815bff5 A |
49 | static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value); |
50 | ||
8459d725 A |
51 | static void NVRamSyncNow(char *name); |
52 | ||
1815bff5 A |
53 | // Global Variables |
54 | static char *gToolName; | |
55 | static io_registry_entry_t gOptionsRef; | |
34d340d7 | 56 | static bool gUseXML; |
9726c137 | 57 | static bool gUseForceSync; |
1815bff5 A |
58 | |
59 | ||
60 | int 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 | // | |
151 | static 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. | |
171 | enum { | |
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 | // | |
190 | static 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 | // | |
311 | static 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 | // |
383 | static 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 | // | |
434 | static 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 | // |
454 | static 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 | // |
519 | static void DeleteOFVariable(char *name) | |
520 | { | |
521 | SetOFVariable(kIONVRAMDeletePropertyKey, name); | |
522 | } | |
523 | ||
8459d725 A |
524 | static 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 | 537 | static 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 | // |
572 | static 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 | // | |
676 | static 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 | ||
690 | static 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 | // | |
704 | static 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 |
741 | static 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 | } |