]> git.saurik.com Git - apple/system_cmds.git/blob - nvram.tproj/nvram.c
9fbbe4d45f06b389550f9d3db1ca1f6243c43503
[apple/system_cmds.git] / nvram.tproj / nvram.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall
27 */
28
29 #include <stdio.h>
30 #include <IOKit/IOKitLib.h>
31 #include <IOKit/IOKitKeys.h>
32 #include <CoreFoundation/CoreFoundation.h>
33
34 // Prototypes
35 static void Error(char *format, long item);
36 static void FatalError(long exitValue, char *format, long item);
37 static void UsageMessage(char *message);
38 static void ParseFile(char *fileName);
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);
43 static void DeleteOFVariable(char *name);
44 static void PrintOFVariables(void);
45 static void PrintOFVariable(const void *key,const void *value,void *context);
46 static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value);
47
48 // Global Variables
49 static char *gToolName;
50 static io_registry_entry_t gOptionsRef;
51
52
53 int main(int argc, char **argv)
54 {
55 long cnt;
56 char *str, errorMessage[256];
57 kern_return_t result;
58 mach_port_t masterPort;
59
60 // Get the name of the command.
61 gToolName = strrchr(argv[0], '/');
62 if (gToolName != 0) gToolName++;
63 else gToolName = argv[0];
64
65 result = IOMasterPort(bootstrap_port, &masterPort);
66 if (result != KERN_SUCCESS) {
67 FatalError(-1, "Error (%d) getting the IOMaster port", result);
68 exit(-1);
69 }
70
71 gOptionsRef = IORegistryEntryFromPath(masterPort, "IODeviceTree:/options");
72 if (gOptionsRef == 0) {
73 FatalError(-1, "Error (%d) getting a reference to /options", -1);
74 exit(-1);
75 }
76
77 for (cnt = 1; cnt < argc; cnt++) {
78 str = argv[cnt];
79 if (str[0] == '-' && str[1] != 0) {
80 // Parse the options.
81 for (str += 1 ; *str; str++) {
82 switch (*str) {
83 case 'p' :
84 PrintOFVariables();
85 break;
86
87 case 'f':
88 cnt++;
89 if (cnt < argc && *argv[cnt] != '-') {
90 ParseFile(argv[cnt]);
91 } else {
92 UsageMessage("missing filename");
93 }
94 break;
95
96 case 'd':
97 cnt++;
98 if (cnt < argc && *argv[cnt] != '-') {
99 DeleteOFVariable(argv[cnt]);
100 } else {
101 UsageMessage("missing name");
102 }
103 break;
104
105 default:
106 strcpy(errorMessage, "no such option as --");
107 errorMessage[strlen(errorMessage)-1] = *str;
108 UsageMessage(errorMessage);
109 }
110 }
111 } else {
112 // Other arguments will be Open Firmware variable requests.
113 SetOrGetOFVariable(str);
114 }
115 }
116
117 IOObjectRelease(gOptionsRef);
118
119 return 0;
120 }
121
122
123 // Error(format, item)
124 //
125 // Print a message on standard error.
126 //
127 static void Error(char *format, long item)
128 {
129 fprintf(stderr, "%s: ", gToolName);
130 fprintf(stderr, format, item);
131 fprintf(stderr, "\n");
132 }
133
134
135 // FatalError(exitValue, format, item)
136 //
137 // Print a message on standard error and exit with value.
138 //
139 static void FatalError(long exitValue, char *format, long item)
140 {
141 fprintf(stderr, "%s: ", gToolName);
142 fprintf(stderr, format, item);
143 fprintf(stderr, "\n");
144
145 exit(exitValue);
146 }
147
148
149 // UsageMessage(message)
150 //
151 // Print the usage information and exit.
152 //
153 static void UsageMessage(char *message)
154 {
155 Error("(usage: %s)", (long)message);
156
157 printf("%s [-p] [-f filename] [-d name] name[=value] ...\n", gToolName);
158 printf("\t-p print all Open Firmware variables\n");
159 printf("\t-f set Open Firmware variables from a text file\n");
160 printf("\t-d delete the named variable\n");
161 printf("\tname=value set named variable\n");
162 printf("\tname print variable\n");
163 printf("Note that arguments and options are executed in order.\n");
164
165 exit(1);
166 }
167
168
169 // States for ParseFile.
170 enum {
171 kFirstColumn = 0,
172 kScanComment,
173 kFindName,
174 kCollectName,
175 kFindValue,
176 kCollectValue,
177 kContinueValue,
178 kSetenv,
179
180 kMaxStringSize = 0x800,
181 kMaxNameSize = 0x100
182 };
183
184
185 // ParseFile(fileName)
186 //
187 // Open and parse the specified file.
188 //
189 static void ParseFile(char *fileName)
190 {
191 long state, tc, ni = 0, vi = 0;
192 char name[kMaxNameSize];
193 char value[kMaxStringSize];
194 FILE *patches;
195
196 patches = fopen(fileName, "r");
197 if (patches == 0) {
198 FatalError(errno, "Couldn't open patch file - '%s'", (long)fileName);
199 }
200
201 state = kFirstColumn;
202 while ((tc = getc(patches)) != EOF) {
203 switch (state) {
204 case kFirstColumn :
205 ni = 0;
206 vi = 0;
207 if (tc == '#') {
208 state = kScanComment;
209 } else if (tc == '\n') {
210 // state stays kFirstColumn.
211 } else if (isspace(tc)) {
212 state = kFindName;
213 } else {
214 state = kCollectName;
215 name[ni++] = tc;
216 }
217 break;
218
219 case kScanComment :
220 if (tc == '\n') {
221 state = kFirstColumn;
222 } else {
223 // state stays kScanComment.
224 }
225 break;
226
227 case kFindName :
228 if (tc == '\n') {
229 state = kFirstColumn;
230 } else if (isspace(tc)) {
231 // state stays kFindName.
232 } else {
233 state = kCollectName;
234 name[ni++] = tc;
235 }
236 break;
237
238 case kCollectName :
239 if (tc == '\n') {
240 name[ni] = 0;
241 Error("Name must be followed by white space - '%s'", (long)name);
242 state = kFirstColumn;
243 } else if (isspace(tc)) {
244 state = kFindValue;
245 } else {
246 name[ni++] = tc;
247 // state staus kCollectName.
248 }
249 break;
250
251 case kFindValue :
252 case kContinueValue :
253 if (tc == '\n') {
254 state = kSetenv;
255 } else if (isspace(tc)) {
256 // state stays kFindValue or kContinueValue.
257 } else {
258 state = kCollectValue;
259 value[vi++] = tc;
260 }
261 break;
262
263 case kCollectValue :
264 if (tc == '\n') {
265 if (value[vi-1] == '\\') {
266 value[vi-1] = '\r';
267 state = kContinueValue;
268 } else {
269 state = kSetenv;
270 }
271 } else {
272 // state stays kCollectValue.
273 value[vi++] = tc;
274 }
275 break;
276 }
277
278 if (state == kSetenv) {
279 name[ni] = 0;
280 value[vi] = 0;
281 if (SetOFVariable(name, value) != KERN_SUCCESS) {
282 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name);
283 }
284 state = kFirstColumn;
285 }
286 }
287
288 if (state != kFirstColumn) {
289 FatalError(-1, "Last line ended abruptly", 0);
290 }
291 }
292
293
294 // SetOrGetOFVariable(str)
295 //
296 // Parse the input string the set or get the specified
297 // Open Firmware variable.
298 //
299 static void SetOrGetOFVariable(char *str)
300 {
301 long set = 0;
302 char *name;
303 char *value;
304 CFStringRef nameRef;
305 CFTypeRef valueRef;
306 kern_return_t result;
307
308 // OF variable name is first.
309 name = str;
310
311 // Find the equal sign for set
312 while (*str) {
313 if (*str == '=') {
314 set = 1;
315 *str++ = '\0';
316 break;
317 }
318 str++;
319 }
320
321 if (set == 1) {
322 // On sets, the OF variable's value follows the equal sign.
323 value = str;
324
325 result = SetOFVariable(name, value);
326 if (result != KERN_SUCCESS) {
327 FatalError(-1, "Error (-1) setting variable - '%s'", (long)name);
328 }
329 } else {
330 result = GetOFVariable(name, &nameRef, &valueRef);
331 if (result != KERN_SUCCESS) {
332 FatalError(-1, "Error (-1) getting variable - '%s'", (long)name);
333 }
334
335 PrintOFVariable(nameRef, valueRef, 0);
336 CFRelease(nameRef);
337 CFRelease(valueRef);
338 }
339 }
340
341
342 // GetOFVariable(name, nameRef, valueRef)
343 //
344 // Get the named Open Firmware variable.
345 // Return it and it's symbol in valueRef and nameRef.
346 //
347 static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
348 CFTypeRef *valueRef)
349 {
350 *nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
351 kCFStringEncodingMacRoman);
352 if (*nameRef == 0) {
353 FatalError(-1, "Error CFString for key %s", (long)name);
354 }
355
356 *valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, *nameRef, 0, 0);
357 if (*valueRef == 0) return -1;
358
359 return KERN_SUCCESS;
360 }
361
362
363 // SetOFVariable(name, value)
364 //
365 // Set or create an Open Firmware variable with name and value.
366 //
367 static kern_return_t SetOFVariable(char *name, char *value)
368 {
369 CFStringRef nameRef;
370 CFTypeRef valueRef;
371 CFTypeID typeID;
372 kern_return_t result;
373
374 nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
375 kCFStringEncodingMacRoman);
376 if (nameRef == 0) {
377 FatalError(-1, "Error (-1) creating CFString for key %s", (long)name);
378 }
379
380 valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, nameRef, 0, 0);
381 if (valueRef) {
382 typeID = CFGetTypeID(valueRef);
383 CFRelease(valueRef);
384
385 valueRef = ConvertValueToCFTypeRef(typeID, value);
386 if (valueRef == 0) {
387 FatalError(-1, "Error (-1) creating CFTypeRef for value %s",(long)value);
388 } result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
389 } else {
390 while (1) {
391 // In the default case, try data, string, number, then boolean.
392
393 valueRef = ConvertValueToCFTypeRef(CFDataGetTypeID(), value);
394 if (valueRef != 0) {
395 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
396 if (result == KERN_SUCCESS) break;
397 }
398
399 valueRef = ConvertValueToCFTypeRef(CFStringGetTypeID(), value);
400 if (valueRef != 0) {
401 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
402 if (result == KERN_SUCCESS) break;
403 }
404
405 valueRef = ConvertValueToCFTypeRef(CFNumberGetTypeID(), value);
406 if (valueRef != 0) {
407 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
408 if (result == KERN_SUCCESS) break;
409 }
410
411 valueRef = ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value);
412 if (valueRef != 0) {
413 result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
414 if (result == KERN_SUCCESS) break;
415 }
416
417 result = -1;
418 break;
419 }
420 }
421
422 CFRelease(nameRef);
423
424 return result;
425 }
426
427
428 // DeleteOFVariable(name)
429 //
430 // Delete the named Open Firmware variable.
431 //
432 //
433 static void DeleteOFVariable(char *name)
434 {
435 SetOFVariable(kIONVRAMDeletePropertyKey, name);
436 }
437
438
439 // PrintOFVariables()
440 //
441 // Print all of the Open Firmware variables.
442 //
443 static void PrintOFVariables()
444 {
445 kern_return_t result;
446 CFMutableDictionaryRef dict;
447
448 result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
449 if (result != KERN_SUCCESS) {
450 FatalError(-1, "Error (%d) getting the Open Firmware variables", result);
451 }
452 CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
453
454 CFRelease(dict);
455 }
456
457
458 // PrintOFVariable(key, value, context)
459 //
460 // Print the given Open Firmware variable.
461 //
462 static void PrintOFVariable(const void *key, const void *value, void *context)
463 {
464 long cnt, cnt2;
465 const char *nameString;
466 char numberBuffer[10];
467 const uint8_t *dataPtr;
468 uint8_t dataChar;
469 char *dataBuffer = 0;
470 const char *valueString = 0;
471 uint32_t number, length;
472 CFTypeID typeID;
473
474 // Get the OF variable's name.
475 nameString = CFStringGetCStringPtr(key, kCFStringEncodingMacRoman);
476
477 // Get the OF variable's type.
478 typeID = CFGetTypeID(value);
479
480 if (typeID == CFBooleanGetTypeID()) {
481 if (CFBooleanGetValue(value)) valueString = "true";
482 else valueString = "false";
483 } else if (typeID == CFNumberGetTypeID()) {
484 CFNumberGetValue(value, kCFNumberSInt32Type, &number);
485 if (number == 0xFFFFFFFF) sprintf(numberBuffer, "-1");
486 else if (number < 1000) sprintf(numberBuffer, "%d", number);
487 else sprintf(numberBuffer, "0x%x", number);
488 valueString = numberBuffer;
489 } else if (typeID == CFStringGetTypeID()) {
490 valueString = CFStringGetCStringPtr(value, kCFStringEncodingMacRoman);
491 } else if (typeID == CFDataGetTypeID()) {
492 length = CFDataGetLength(value);
493 if (length == 0) valueString = "";
494 else {
495 dataBuffer = malloc(length * 3 + 1);
496 if (dataBuffer != 0) {
497 dataPtr = CFDataGetBytePtr(value);
498 for (cnt = cnt2 = 0; cnt < length; cnt++) {
499 dataChar = dataPtr[cnt];
500 if (isprint(dataChar)) dataBuffer[cnt2++] = dataChar;
501 else {
502 sprintf(dataBuffer + cnt2, "%%%02x", dataChar);
503 cnt2 += 3;
504 }
505 }
506 dataBuffer[cnt2] = '\0';
507 valueString = dataBuffer;
508 }
509 }
510 } else return;
511
512 if ((nameString != 0) && (valueString != 0))
513 printf("%s\t%s\n", nameString, valueString);
514
515 if (dataBuffer != 0) free(dataBuffer);
516 }
517
518
519 // ConvertValueToCFTypeRef(typeID, value)
520 //
521 // Convert the value into a CFType given the typeID.
522 //
523 static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value)
524 {
525 CFTypeRef valueRef = 0;
526 long cnt, cnt2, length;
527 unsigned long number, tmp;
528
529 if (typeID == CFBooleanGetTypeID()) {
530 if (!strcmp("true", value)) valueRef = kCFBooleanTrue;
531 else if (!strcmp("false", value)) valueRef = kCFBooleanFalse;
532 } else if (typeID == CFNumberGetTypeID()) {
533 number = strtol(value, 0, 0);
534 valueRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type,
535 &number);
536 } else if (typeID == CFStringGetTypeID()) {
537 valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value,
538 kCFStringEncodingMacRoman);
539 } else if (typeID == CFDataGetTypeID()) {
540 length = strlen(value);
541 for (cnt = cnt2 = 0; cnt < length; cnt++, cnt2++) {
542 if (value[cnt] == '%') {
543 if (!ishexnumber(value[cnt + 1]) ||
544 !ishexnumber(value[cnt + 2])) return 0;
545 number = toupper(value[++cnt]) - '0';
546 if (number > 9) number -= 7;
547 tmp = toupper(value[++cnt]) - '0';
548 if (tmp > 9) tmp -= 7;
549 number = (number << 4) + tmp;
550 value[cnt2] = number;
551 } else value[cnt2] = value[cnt];
552 }
553 valueRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, value,
554 cnt2, kCFAllocatorDefault);
555 } else return 0;
556
557 return valueRef;
558 }