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