]> git.saurik.com Git - apple/system_cmds.git/blob - nvram.tproj/nvram.c
d97fb9d97e3e100f0d9aac9f46978fc73ea3242e
[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 SetOrGetOFVariable(char *str);
37 static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
38 CFTypeRef *valueRef);
39 static kern_return_t SetOFVariable(char *name, char *value);
40 static void DeleteOFVariable(char *name);
41 static void PrintOFVariables(void);
42 static void PrintOFVariable(const void *key,const void *value,void *context);
43 static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value);
44
45 // Global Variables
46 static char *gToolName;
47 static io_registry_entry_t gOptionsRef;
48
49
50 int main(int argc, char **argv)
51 {
52 long cnt;
53 char *str, errorMessage[256];
54 kern_return_t result;
55 mach_port_t masterPort;
56
57 // Get the name of the command.
58 gToolName = strrchr(argv[0], '/');
59 if (gToolName != 0) gToolName++;
60 else gToolName = argv[0];
61
62 result = IOMasterPort(bootstrap_port, &masterPort);
63 if (result != KERN_SUCCESS) {
64 FatalError(-1, "Error (%d) getting the IOMaster port", result);
65 exit(-1);
66 }
67
68 gOptionsRef = IORegistryEntryFromPath(masterPort, "IODeviceTree:/options");
69 if (gOptionsRef == 0) {
70 FatalError(-1, "nvram is not supported on this system.", -1);
71 exit(-1);
72 }
73
74 for (cnt = 1; cnt < argc; cnt++) {
75 str = argv[cnt];
76 if (str[0] == '-' && str[1] != 0) {
77 // Parse the options.
78 for (str += 1 ; *str; str++) {
79 switch (*str) {
80 case 'p' :
81 PrintOFVariables();
82 break;
83
84 case 'f':
85 cnt++;
86 if (cnt < argc && *argv[cnt] != '-') {
87 ParseFile(argv[cnt]);
88 } else {
89 UsageMessage("missing filename");
90 }
91 break;
92
93 case 'd':
94 cnt++;
95 if (cnt < argc && *argv[cnt] != '-') {
96 DeleteOFVariable(argv[cnt]);
97 } else {
98 UsageMessage("missing name");
99 }
100 break;
101
102 default:
103 strcpy(errorMessage, "no such option as --");
104 errorMessage[strlen(errorMessage)-1] = *str;
105 UsageMessage(errorMessage);
106 }
107 }
108 } else {
109 // Other arguments will be firmware variable requests.
110 SetOrGetOFVariable(str);
111 }
112 }
113
114 IOObjectRelease(gOptionsRef);
115
116 return 0;
117 }
118
119
120 // Error(format, item)
121 //
122 // Print a message on standard error.
123 //
124 static void Error(char *format, long item)
125 {
126 fprintf(stderr, "%s: ", gToolName);
127 fprintf(stderr, format, item);
128 fprintf(stderr, "\n");
129 }
130
131
132 // FatalError(exitValue, format, item)
133 //
134 // Print a message on standard error and exit with value.
135 //
136 static void FatalError(long exitValue, char *format, long item)
137 {
138 fprintf(stderr, "%s: ", gToolName);
139 fprintf(stderr, format, item);
140 fprintf(stderr, "\n");
141
142 exit(exitValue);
143 }
144
145
146 // UsageMessage(message)
147 //
148 // Print the usage information and exit.
149 //
150 static void UsageMessage(char *message)
151 {
152 Error("(usage: %s)", (long)message);
153
154 printf("%s [-p] [-f filename] [-d name] name[=value] ...\n", gToolName);
155 printf("\t-p print all firmware variables\n");
156 printf("\t-f set firmware variables from a text file\n");
157 printf("\t-d delete the named variable\n");
158 printf("\tname=value set named variable\n");
159 printf("\tname print variable\n");
160 printf("Note that arguments and options are executed in order.\n");
161
162 exit(1);
163 }
164
165
166 // States for ParseFile.
167 enum {
168 kFirstColumn = 0,
169 kScanComment,
170 kFindName,
171 kCollectName,
172 kFindValue,
173 kCollectValue,
174 kContinueValue,
175 kSetenv,
176
177 kMaxStringSize = 0x800,
178 kMaxNameSize = 0x100
179 };
180
181
182 // ParseFile(fileName)
183 //
184 // Open and parse the specified file.
185 //
186 static void ParseFile(char *fileName)
187 {
188 long state, tc, ni = 0, vi = 0;
189 char name[kMaxNameSize];
190 char value[kMaxStringSize];
191 FILE *patches;
192
193 patches = fopen(fileName, "r");
194 if (patches == 0) {
195 FatalError(errno, "Couldn't open patch file - '%s'", (long)fileName);
196 }
197
198 state = kFirstColumn;
199 while ((tc = getc(patches)) != EOF) {
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;
238 Error("Name must be followed by white space - '%s'", (long)name);
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;
278 if (SetOFVariable(name, value) != KERN_SUCCESS) {
279 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name);
280 }
281 state = kFirstColumn;
282 }
283 }
284
285 if (state != kFirstColumn) {
286 FatalError(-1, "Last line ended abruptly", 0);
287 }
288 }
289
290
291 // SetOrGetOFVariable(str)
292 //
293 // Parse the input string, then set or get the specified
294 // firmware variable.
295 //
296 static void SetOrGetOFVariable(char *str)
297 {
298 long set = 0;
299 char *name;
300 char *value;
301 CFStringRef nameRef;
302 CFTypeRef valueRef;
303 kern_return_t result;
304
305 // OF variable name is first.
306 name = str;
307
308 // Find the equal sign for set
309 while (*str) {
310 if (*str == '=') {
311 set = 1;
312 *str++ = '\0';
313 break;
314 }
315 str++;
316 }
317
318 if (set == 1) {
319 // On sets, the OF variable's value follows the equal sign.
320 value = str;
321
322 result = SetOFVariable(name, value);
323 if (result != KERN_SUCCESS) {
324 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name);
325 }
326 } else {
327 result = GetOFVariable(name, &nameRef, &valueRef);
328 if (result != KERN_SUCCESS) {
329 FatalError(-1, "Error (-1) getting variable - '%s'", (long)name);
330 }
331
332 PrintOFVariable(nameRef, valueRef, 0);
333 CFRelease(nameRef);
334 CFRelease(valueRef);
335 }
336 }
337
338
339 // GetOFVariable(name, nameRef, valueRef)
340 //
341 // Get the named firmware variable.
342 // Return it and it's symbol in valueRef and nameRef.
343 //
344 static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
345 CFTypeRef *valueRef)
346 {
347 *nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
348 kCFStringEncodingUTF8);
349 if (*nameRef == 0) {
350 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name);
351 }
352
353 *valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, *nameRef, 0, 0);
354 if (*valueRef == 0) return -1;
355
356 return KERN_SUCCESS;
357 }
358
359
360 // SetOFVariable(name, value)
361 //
362 // Set or create an firmware variable with name and value.
363 //
364 static kern_return_t SetOFVariable(char *name, char *value)
365 {
366 CFStringRef nameRef;
367 CFTypeRef valueRef;
368 CFTypeID typeID;
369 kern_return_t result;
370
371 nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
372 kCFStringEncodingUTF8);
373 if (nameRef == 0) {
374 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name);
375 }
376
377 valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, nameRef, 0, 0);
378 if (valueRef) {
379 typeID = CFGetTypeID(valueRef);
380 CFRelease(valueRef);
381
382 valueRef = ConvertValueToCFTypeRef(typeID, value);
383 if (valueRef == 0) {
384 FatalError(-1, "Error (-1) creating CFTypeRef for value %s",(long)value);
385 } result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
386 } else {
387 while (1) {
388 // In the default case, try data, string, number, then boolean.
389
390 valueRef = ConvertValueToCFTypeRef(CFDataGetTypeID(), value);
391 if (valueRef != 0) {
392 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
393 if (result == KERN_SUCCESS) break;
394 }
395
396 valueRef = ConvertValueToCFTypeRef(CFStringGetTypeID(), value);
397 if (valueRef != 0) {
398 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
399 if (result == KERN_SUCCESS) break;
400 }
401
402 valueRef = ConvertValueToCFTypeRef(CFNumberGetTypeID(), value);
403 if (valueRef != 0) {
404 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
405 if (result == KERN_SUCCESS) break;
406 }
407
408 valueRef = ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value);
409 if (valueRef != 0) {
410 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
411 if (result == KERN_SUCCESS) break;
412 }
413
414 result = -1;
415 break;
416 }
417 }
418
419 CFRelease(nameRef);
420
421 return result;
422 }
423
424
425 // DeleteOFVariable(name)
426 //
427 // Delete the named firmware variable.
428 //
429 //
430 static void DeleteOFVariable(char *name)
431 {
432 SetOFVariable(kIONVRAMDeletePropertyKey, name);
433 }
434
435
436 // PrintOFVariables()
437 //
438 // Print all of the firmware variables.
439 //
440 static void PrintOFVariables()
441 {
442 kern_return_t result;
443 CFMutableDictionaryRef dict;
444
445 result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
446 if (result != KERN_SUCCESS) {
447 FatalError(-1, "Error (%d) getting the firmware variables", result);
448 }
449 CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
450
451 CFRelease(dict);
452 }
453
454
455 // PrintOFVariable(key, value, context)
456 //
457 // Print the given firmware variable.
458 //
459 static void PrintOFVariable(const void *key, const void *value, void *context)
460 {
461 long cnt, cnt2;
462 CFIndex nameLen;
463 char *nameBuffer = 0;
464 const char *nameString;
465 char numberBuffer[10];
466 const uint8_t *dataPtr;
467 uint8_t dataChar;
468 char *dataBuffer = 0;
469 CFIndex valueLen;
470 char *valueBuffer = 0;
471 const char *valueString = 0;
472 uint32_t number, length;
473 CFTypeID typeID;
474
475 // Get the OF variable's name.
476 nameLen = CFStringGetLength(key) + 1;
477 nameBuffer = malloc(nameLen);
478 if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
479 nameString = nameBuffer;
480 else {
481 Error("Error (-1) Unable to convert property name to C string", 0);
482 nameString = "<UNPRINTABLE>";
483 }
484
485 // Get the OF variable's type.
486 typeID = CFGetTypeID(value);
487
488 if (typeID == CFBooleanGetTypeID()) {
489 if (CFBooleanGetValue(value)) valueString = "true";
490 else valueString = "false";
491 } else if (typeID == CFNumberGetTypeID()) {
492 CFNumberGetValue(value, kCFNumberSInt32Type, &number);
493 if (number == 0xFFFFFFFF) sprintf(numberBuffer, "-1");
494 else if (number < 1000) sprintf(numberBuffer, "%d", number);
495 else sprintf(numberBuffer, "0x%x", number);
496 valueString = numberBuffer;
497 } else if (typeID == CFStringGetTypeID()) {
498 valueLen = CFStringGetLength(value) + 1;
499 valueBuffer = malloc(valueLen + 1);
500 if ( valueBuffer && CFStringGetCString(value, valueBuffer, valueLen, kCFStringEncodingUTF8) )
501 valueString = valueBuffer;
502 else {
503 Error("Error (-1) Unable to convert value to C string", 0);
504 valueString = "<UNPRINTABLE>";
505 }
506 } else if (typeID == CFDataGetTypeID()) {
507 length = CFDataGetLength(value);
508 if (length == 0) valueString = "";
509 else {
510 dataBuffer = malloc(length * 3 + 1);
511 if (dataBuffer != 0) {
512 dataPtr = CFDataGetBytePtr(value);
513 for (cnt = cnt2 = 0; cnt < length; cnt++) {
514 dataChar = dataPtr[cnt];
515 if (isprint(dataChar)) dataBuffer[cnt2++] = dataChar;
516 else {
517 sprintf(dataBuffer + cnt2, "%%%02x", dataChar);
518 cnt2 += 3;
519 }
520 }
521 dataBuffer[cnt2] = '\0';
522 valueString = dataBuffer;
523 }
524 }
525 } else {
526 valueString="<INVALID>";
527 }
528
529 if ((nameString != 0) && (valueString != 0))
530 printf("%s\t%s\n", nameString, valueString);
531
532 if (dataBuffer != 0) free(dataBuffer);
533 if (nameBuffer != 0) free(nameBuffer);
534 if (valueBuffer != 0) free(valueBuffer);
535 }
536
537
538 // ConvertValueToCFTypeRef(typeID, value)
539 //
540 // Convert the value into a CFType given the typeID.
541 //
542 static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value)
543 {
544 CFTypeRef valueRef = 0;
545 long cnt, cnt2, length;
546 unsigned long number, tmp;
547
548 if (typeID == CFBooleanGetTypeID()) {
549 if (!strcmp("true", value)) valueRef = kCFBooleanTrue;
550 else if (!strcmp("false", value)) valueRef = kCFBooleanFalse;
551 } else if (typeID == CFNumberGetTypeID()) {
552 number = strtol(value, 0, 0);
553 valueRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type,
554 &number);
555 } else if (typeID == CFStringGetTypeID()) {
556 valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value,
557 kCFStringEncodingUTF8);
558 } else if (typeID == CFDataGetTypeID()) {
559 length = strlen(value);
560 for (cnt = cnt2 = 0; cnt < length; cnt++, cnt2++) {
561 if (value[cnt] == '%') {
562 if (!ishexnumber(value[cnt + 1]) ||
563 !ishexnumber(value[cnt + 2])) return 0;
564 number = toupper(value[++cnt]) - '0';
565 if (number > 9) number -= 7;
566 tmp = toupper(value[++cnt]) - '0';
567 if (tmp > 9) tmp -= 7;
568 number = (number << 4) + tmp;
569 value[cnt2] = number;
570 } else value[cnt2] = value[cnt];
571 }
572 valueRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, value,
573 cnt2, kCFAllocatorDefault);
574 } else return 0;
575
576 return valueRef;
577 }
578