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