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