]> git.saurik.com Git - apple/system_cmds.git/blame - nvram.tproj/nvram.c
system_cmds-336.23.tar.gz
[apple/system_cmds.git] / nvram.tproj / nvram.c
CommitLineData
1815bff5 1/*
2fc1e207 2 * Copyright (c) 2000-2005 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 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>
1815bff5
A
29#include <CoreFoundation/CoreFoundation.h>
30
31// Prototypes
32static void Error(char *format, long item);
33static void FatalError(long exitValue, char *format, long item);
34static void UsageMessage(char *message);
35static void ParseFile(char *fileName);
36static void SetOrGetOFVariable(char *str);
37static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
38 CFTypeRef *valueRef);
39static kern_return_t SetOFVariable(char *name, char *value);
83f6dbe8 40static void DeleteOFVariable(char *name);
1815bff5
A
41static void PrintOFVariables(void);
42static void PrintOFVariable(const void *key,const void *value,void *context);
43static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value);
44
45// Global Variables
46static char *gToolName;
47static io_registry_entry_t gOptionsRef;
48
49
50int 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) {
09fd88e4 70 FatalError(-1, "nvram is not supported on this system.", -1);
1815bff5
A
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
83f6dbe8
A
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
1815bff5
A
102 default:
103 strcpy(errorMessage, "no such option as --");
104 errorMessage[strlen(errorMessage)-1] = *str;
105 UsageMessage(errorMessage);
106 }
107 }
108 } else {
4c00c0ae 109 // Other arguments will be firmware variable requests.
1815bff5
A
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//
124static 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//
136static 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//
150static void UsageMessage(char *message)
151{
152 Error("(usage: %s)", (long)message);
153
83f6dbe8 154 printf("%s [-p] [-f filename] [-d name] name[=value] ...\n", gToolName);
4c00c0ae
A
155 printf("\t-p print all firmware variables\n");
156 printf("\t-f set firmware variables from a text file\n");
83f6dbe8 157 printf("\t-d delete the named variable\n");
1815bff5
A
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.
167enum {
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//
186static 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//
2fc1e207 293// Parse the input string, then set or get the specified
4c00c0ae 294// firmware variable.
1815bff5
A
295//
296static 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//
4c00c0ae 341// Get the named firmware variable.
1815bff5
A
342// Return it and it's symbol in valueRef and nameRef.
343//
344static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
345 CFTypeRef *valueRef)
346{
347 *nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
2fc1e207 348 kCFStringEncodingUTF8);
1815bff5 349 if (*nameRef == 0) {
2fc1e207 350 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name);
1815bff5
A
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//
4c00c0ae 362// Set or create an firmware variable with name and value.
1815bff5
A
363//
364static 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,
2fc1e207 372 kCFStringEncodingUTF8);
1815bff5
A
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);
20e66415
A
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 }
1815bff5
A
417 }
418
1815bff5
A
419 CFRelease(nameRef);
420
421 return result;
422}
423
424
83f6dbe8
A
425// DeleteOFVariable(name)
426//
4c00c0ae 427// Delete the named firmware variable.
83f6dbe8
A
428//
429//
430static void DeleteOFVariable(char *name)
431{
432 SetOFVariable(kIONVRAMDeletePropertyKey, name);
433}
434
435
1815bff5
A
436// PrintOFVariables()
437//
4c00c0ae 438// Print all of the firmware variables.
1815bff5
A
439//
440static void PrintOFVariables()
441{
442 kern_return_t result;
443 CFMutableDictionaryRef dict;
444
445 result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
446 if (result != KERN_SUCCESS) {
4c00c0ae 447 FatalError(-1, "Error (%d) getting the firmware variables", result);
1815bff5
A
448 }
449 CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
450
451 CFRelease(dict);
452}
453
454
455// PrintOFVariable(key, value, context)
456//
4c00c0ae 457// Print the given firmware variable.
1815bff5
A
458//
459static void PrintOFVariable(const void *key, const void *value, void *context)
460{
461 long cnt, cnt2;
2fc1e207
A
462 CFIndex nameLen;
463 char *nameBuffer = 0;
1815bff5
A
464 const char *nameString;
465 char numberBuffer[10];
b51d5b5f
A
466 const uint8_t *dataPtr;
467 uint8_t dataChar;
1815bff5 468 char *dataBuffer = 0;
2fc1e207
A
469 CFIndex valueLen;
470 char *valueBuffer = 0;
b51d5b5f
A
471 const char *valueString = 0;
472 uint32_t number, length;
1815bff5
A
473 CFTypeID typeID;
474
475 // Get the OF variable's name.
2fc1e207
A
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 }
1815bff5
A
484
485 // Get the OF variable's type.
486 typeID = CFGetTypeID(value);
487
2fc1e207 488 if (typeID == CFBooleanGetTypeID()) {
1815bff5
A
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()) {
2fc1e207
A
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 }
1815bff5
A
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 }
2fc1e207
A
525 } else {
526 valueString="<INVALID>";
527 }
1815bff5
A
528
529 if ((nameString != 0) && (valueString != 0))
530 printf("%s\t%s\n", nameString, valueString);
531
532 if (dataBuffer != 0) free(dataBuffer);
2fc1e207
A
533 if (nameBuffer != 0) free(nameBuffer);
534 if (valueBuffer != 0) free(valueBuffer);
1815bff5
A
535}
536
537
538// ConvertValueToCFTypeRef(typeID, value)
539//
540// Convert the value into a CFType given the typeID.
541//
542static 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,
2fc1e207 557 kCFStringEncodingUTF8);
1815bff5
A
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}
09fd88e4 578