1 | /*␊ |
2 | * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.␊ |
3 | *␊ |
4 | * @APPLE_LICENSE_HEADER_START@␊ |
5 | * ␊ |
6 | * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights␊ |
7 | * Reserved. This file contains Original Code and/or Modifications of␊ |
8 | * Original Code as defined in and that are subject to the Apple Public␊ |
9 | * Source License Version 2.0 (the "License"). You may not use this file␊ |
10 | * except in compliance with the License. Please obtain a copy of the␊ |
11 | * License at http://www.apple.com/publicsource and read it before using␊ |
12 | * this file.␊ |
13 | * ␊ |
14 | * The Original Code and all software distributed under the License are␊ |
15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER␊ |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,␊ |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,␊ |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the␊ |
19 | * License for the specific language governing rights and limitations␊ |
20 | * under the License.␊ |
21 | * ␊ |
22 | * @APPLE_LICENSE_HEADER_END@␊ |
23 | */␊ |
24 | /*␊ |
25 | * Copyright 1993 NeXT, Inc.␊ |
26 | * All rights reserved.␊ |
27 | */␊ |
28 | ␊ |
29 | #include "bootstruct.h"␊ |
30 | #include "libsaio.h"␊ |
31 | #include "boot.h"␊ |
32 | #include "xml.h"␊ |
33 | ␊ |
34 | extern char *Language;␊ |
35 | extern char *LoadableFamilies;␊ |
36 | ␊ |
37 | bool sysConfigValid;␊ |
38 | ␊ |
39 | #if UNUSED␊ |
40 | /*␊ |
41 | * Compare a string to a key with quoted characters␊ |
42 | */␊ |
43 | static inline int␊ |
44 | keyncmp(const char *str, const char *key, int n)␊ |
45 | {␊ |
46 | int c;␊ |
47 | while (n--) {␊ |
48 | ␉c = *key++;␊ |
49 | ␉if (c == '\\') {␊ |
50 | ␉ switch(c = *key++) {␊ |
51 | ␉ case 'n':␊ |
52 | ␉␉c = '\n';␊ |
53 | ␉␉break;␊ |
54 | ␉ case 'r':␊ |
55 | ␉␉c = '\r';␊ |
56 | ␉␉break;␊ |
57 | ␉ case 't':␊ |
58 | ␉␉c = '\t';␊ |
59 | ␉␉break;␊ |
60 | ␉ default:␊ |
61 | ␉␉break;␊ |
62 | ␉ }␊ |
63 | ␉} else if (c == '\"') {␊ |
64 | ␉ // Premature end of key␊ |
65 | ␉ return 1;␊ |
66 | ␉}␊ |
67 | ␉if (c != *str++) {␊ |
68 | ␉ return 1;␊ |
69 | ␉}␊ |
70 | }␊ |
71 | return 0;␊ |
72 | }␊ |
73 | ␊ |
74 | static void eatThru(char val, const char **table_p)␊ |
75 | {␊ |
76 | ␉register const char *table = *table_p;␊ |
77 | ␉register bool found = false;␊ |
78 | ␊ |
79 | ␉while (*table && !found)␊ |
80 | ␉{␊ |
81 | ␉␉if (*table == '\\') table += 2;␊ |
82 | ␉␉else␊ |
83 | ␉␉{␊ |
84 | ␉␉␉if (*table == val) found = true;␊ |
85 | ␉␉␉table++;␊ |
86 | ␉␉}␊ |
87 | ␉}␊ |
88 | ␉*table_p = table;␊ |
89 | }␊ |
90 | ␊ |
91 | /* Remove key and its associated value from the table. */␊ |
92 | ␊ |
93 | bool␊ |
94 | removeKeyFromTable(const char *key, char *table)␊ |
95 | {␊ |
96 | register int len;␊ |
97 | register char *tab;␊ |
98 | char *buf;␊ |
99 | ␊ |
100 | len = strlen(key);␊ |
101 | tab = (char *)table;␊ |
102 | buf = (char *)malloc(len + 3);␊ |
103 | ␊ |
104 | sprintf(buf, "\"%s\"", key);␊ |
105 | len = strlen(buf);␊ |
106 | ␊ |
107 | while(*tab) {␊ |
108 | if(strncmp(buf, tab, len) == 0) {␊ |
109 | char c;␊ |
110 | ␊ |
111 | while((c = *(tab + len)) != ';') {␊ |
112 | if(c == 0) {␊ |
113 | len = -1;␊ |
114 | goto out;␊ |
115 | }␊ |
116 | len++;␊ |
117 | }␊ |
118 | len++;␊ |
119 | if(*(tab + len) == '\n') len++;␊ |
120 | goto out;␊ |
121 | }␊ |
122 | tab++;␊ |
123 | }␊ |
124 | len = -1;␊ |
125 | out:␊ |
126 | free(buf);␊ |
127 | ␊ |
128 | if(len == -1) return false;␊ |
129 | ␊ |
130 | while((*tab = *(tab + len))) {␊ |
131 | tab++;␊ |
132 | }␊ |
133 | ␊ |
134 | return true;␊ |
135 | }␊ |
136 | ␊ |
137 | char *newStringFromList(char **list, int *size)␊ |
138 | {␊ |
139 | ␉char *begin = *list, *end;␊ |
140 | ␉char *newstr;␊ |
141 | ␉int newsize = *size;␊ |
142 | ␉int bufsize;␊ |
143 | ␊ |
144 | ␉while (*begin && newsize && isspace(*begin)) {␊ |
145 | ␉␉begin++;␊ |
146 | ␉␉newsize--;␊ |
147 | ␉}␊ |
148 | ␉end = begin;␊ |
149 | ␉while (*end && newsize && !isspace(*end)) {␊ |
150 | ␉␉end++;␊ |
151 | ␉␉newsize--;␊ |
152 | ␉}␊ |
153 | ␉if (begin == end) {␊ |
154 | ␉␉return 0;␊ |
155 | ␉}␊ |
156 | ␉bufsize = end - begin + 1;␊ |
157 | ␉newstr = malloc(bufsize);␊ |
158 | ␉strlcpy(newstr, begin, bufsize);␊ |
159 | ␉*list = end;␊ |
160 | ␉*size = newsize;␊ |
161 | ␉return newstr;␊ |
162 | }␊ |
163 | ␊ |
164 | #endif␊ |
165 | ␊ |
166 | /* ␊ |
167 | * compress == compress escaped characters to one character␊ |
168 | */␊ |
169 | int stringLength(const char *table, int compress)␊ |
170 | {␊ |
171 | ␉int ret = 0;␊ |
172 | ␊ |
173 | ␉while (*table) {␊ |
174 | ␉␉if (*table == '\\') {␊ |
175 | ␉␉␉table += 2;␊ |
176 | ␉␉␉ret += 1 + (compress ? 0 : 1);␊ |
177 | ␉␉} else {␊ |
178 | ␉␉␉if (*table == '\"') {␊ |
179 | ␉␉␉␉return ret;␊ |
180 | ␉␉␉}␊ |
181 | ␉␉␉ret++;␊ |
182 | ␉␉␉table++;␊ |
183 | ␉␉}␊ |
184 | ␉}␊ |
185 | ␉return ret;␊ |
186 | }␊ |
187 | ␊ |
188 | ␊ |
189 | bool getValueForConfigTableKey(config_file_t *config, const char *key, const char **val, int *size)␊ |
190 | {␊ |
191 | ␉if (config->dictionary != 0 ) {␊ |
192 | ␉␉// Look up key in XML dictionary␊ |
193 | ␉␉TagPtr value;␊ |
194 | ␉␉value = XMLGetProperty(config->dictionary, key);␊ |
195 | ␉␉if (value != 0) {␊ |
196 | ␉␉␉if (value->type != kTagTypeString) {␊ |
197 | ␉␉␉␉error("Non-string tag '%s' found in config file\n", key);␊ |
198 | ␉␉␉␉return false;␊ |
199 | ␉␉␉}␊ |
200 | ␉␉␉*val = value->string;␊ |
201 | ␉␉␉*size = strlen(value->string);␊ |
202 | ␉␉␉return true;␊ |
203 | ␉␉}␊ |
204 | ␉} else {␊ |
205 | ␊ |
206 | ␉␉// Legacy plist-style table␊ |
207 | ␊ |
208 | ␉}␊ |
209 | ␊ |
210 | ␉return false;␊ |
211 | }␊ |
212 | ␊ |
213 | #if UNUSED␊ |
214 | ␊ |
215 | /*␊ |
216 | * Returns a new malloc'ed string if one is found␊ |
217 | * in the string table matching 'key'. Also translates␊ |
218 | * \n escapes in the string.␊ |
219 | */␊ |
220 | char *newStringForStringTableKey(char *table, char *key, config_file_t *config)␊ |
221 | {␊ |
222 | ␉const char *val;␊ |
223 | ␉char *newstr, *p;␊ |
224 | ␉int size;␊ |
225 | ␊ |
226 | ␉if (getValueForConfigTableKey(config, key, &val, &size)) {␊ |
227 | ␉␉newstr = (char *)malloc(size+1);␊ |
228 | ␉␉for (p = newstr; size; size--, p++, val++) {␊ |
229 | ␉␉␉if ((*p = *val) == '\\') {␊ |
230 | ␉␉␉␉switch (*++val) {␊ |
231 | ␉␉␉␉␉case 'r':␊ |
232 | ␉␉␉␉␉␉*p = '\r';␊ |
233 | ␉␉␉␉␉break;␊ |
234 | ␉␉␉␉␉case 'n':␊ |
235 | ␉␉␉␉␉␉*p = '\n';␊ |
236 | ␉␉␉␉␉break;␊ |
237 | ␉␉␉␉␉case 't':␊ |
238 | ␉␉␉␉␉␉*p = '\t';␊ |
239 | ␉␉␉␉␉break;␊ |
240 | ␉␉␉␉␉default:␊ |
241 | ␉␉␉␉␉␉*p = *val;␊ |
242 | ␉␉␉␉␉break;␊ |
243 | ␉␉␉␉}␊ |
244 | ␉␉␉␉size--;␊ |
245 | ␉␉␉}␊ |
246 | ␉␉}␊ |
247 | ␉␉*p = '\0';␊ |
248 | ␉␉return newstr;␊ |
249 | ␉} else {␊ |
250 | ␉␉return 0;␊ |
251 | ␉}␊ |
252 | }␊ |
253 | ␊ |
254 | #endif␊ |
255 | ␊ |
256 | char *␊ |
257 | newStringForKey(char *key, config_file_t *config)␊ |
258 | {␊ |
259 | ␉const char *val;␊ |
260 | ␉char *newstr;␊ |
261 | ␉int size;␊ |
262 | ␊ |
263 | ␉if (getValueForKey(key, &val, &size, config) && size) {␊ |
264 | ␉␉newstr = (char *)malloc(size + 1);␊ |
265 | ␉␉strlcpy(newstr, val, size + 1);␊ |
266 | ␉␉return newstr;␊ |
267 | ␉} else {␊ |
268 | ␉␉return 0;␊ |
269 | ␉}␊ |
270 | }␊ |
271 | ␊ |
272 | /* parse a command line␊ |
273 | * in the form: [<argument> ...] [<option>=<value> ...]␊ |
274 | * both <option> and <value> must be either composed of␊ |
275 | * non-whitespace characters, or enclosed in quotes.␊ |
276 | */␊ |
277 | ␊ |
278 | static const char *getToken(const char *line, const char **begin, int *len)␊ |
279 | {␊ |
280 | ␉if (*line == '\"') {␊ |
281 | ␉␉*begin = ++line;␊ |
282 | ␉␉while (*line && *line != '\"') {␊ |
283 | ␉␉␉line++;␊ |
284 | ␉␉}␊ |
285 | ␉␉*len = line++ - *begin;␊ |
286 | ␉} else {␊ |
287 | ␉␉*begin = line;␊ |
288 | ␉␉while (*line && !isspace(*line) && *line != '=') {␊ |
289 | ␉␉␉line++;␊ |
290 | ␉␉}␊ |
291 | ␉␉*len = line - *begin;␊ |
292 | ␉}␊ |
293 | ␉return line;␊ |
294 | }␊ |
295 | ␊ |
296 | bool getValueForBootKey(const char *line, const char *match, const char **matchval, int *len)␊ |
297 | {␊ |
298 | ␉const char *key, *value;␊ |
299 | ␉int key_len, value_len;␊ |
300 | ␉bool retval = false;␊ |
301 | ␊ |
302 | ␉while (*line) {␊ |
303 | ␉␉/* look for keyword or argument */␊ |
304 | ␉␉while (isspace(*line)) {␊ |
305 | ␉␉␉line++;␊ |
306 | ␉␉}␊ |
307 | ␊ |
308 | ␉␉/* now look for '=' or whitespace */␊ |
309 | ␉␉line = getToken(line, &key, &key_len);␊ |
310 | ␉␉/* line now points to '=' or space */␊ |
311 | ␉␉if (*line && !isspace(*line)) {␊ |
312 | ␉␉␉line = getToken(++line, &value, &value_len);␊ |
313 | ␉␉} else {␊ |
314 | ␉␉␉value = line;␊ |
315 | ␉␉␉value_len = 0;␊ |
316 | ␉␉}␊ |
317 | ␉␉if ((strlen(match) == key_len) && strncmp(match, key, key_len) == 0) {␊ |
318 | ␉␉␉// create a new string␊ |
319 | ␉␉␉char* newstr = malloc(value_len + 1);␊ |
320 | ␉␉␉strncpy(newstr, value, value_len);␊ |
321 | ␉␉␉newstr[value_len] = 0;␊ |
322 | ␉␉␊ |
323 | ␉␉␉*matchval = newstr;␊ |
324 | ␉␉␉*len = value_len;␊ |
325 | ␉␉␉retval = true;␊ |
326 | ␉␉␉/* Continue to look for this key; last one wins. */␊ |
327 | ␉␉}␊ |
328 | ␉}␊ |
329 | ␊ |
330 | ␉return retval;␊ |
331 | }␊ |
332 | ␊ |
333 | /* Return NULL if no option has been successfully retrieved, or the string otherwise */␊ |
334 | const char * getStringForKey(const char * key, config_file_t *config)␊ |
335 | {␊ |
336 | ␉static const char* value =0;␊ |
337 | ␉int len=0;␊ |
338 | ␉if(!getValueForKey(key, &value, &len, config)) {␊ |
339 | ␉␉value = 0;␊ |
340 | ␉}␊ |
341 | ␉return value;␊ |
342 | }␊ |
343 | ␊ |
344 | ␊ |
345 | /* Returns TRUE if a value was found, FALSE otherwise.␊ |
346 | * The boolean value of the key is stored in 'val'.␊ |
347 | */␊ |
348 | ␊ |
349 | bool getBoolForKey( const char *key, bool *result_val, config_file_t *config )␊ |
350 | {␊ |
351 | const char *key_val;␊ |
352 | int size;␊ |
353 | ␊ |
354 | ␉if (getValueForKey(key, &key_val, &size, config)) {␊ |
355 | ␉␉if ( (size >= 1) && (key_val[0] == 'Y' || key_val[0] == 'y') ) {␊ |
356 | ␉␉␉*result_val = true;␊ |
357 | ␉␉} else {␊ |
358 | ␉␉␉*result_val = false;␊ |
359 | ␉␉}␊ |
360 | ␉␉return true;␊ |
361 | ␉}␊ |
362 | ␉return false;␊ |
363 | }␊ |
364 | ␊ |
365 | bool getIntForKey( const char *key, int *value, config_file_t *config )␊ |
366 | {␊ |
367 | ␉const char *val;␊ |
368 | ␉int size, sum;␊ |
369 | ␉bool negative = false;␊ |
370 | ␊ |
371 | ␉if (getValueForKey(key, &val, &size, config)) {␊ |
372 | ␉␉if ( size ) {␊ |
373 | ␉␉␉if (*val == '-') {␊ |
374 | ␉␉␉␉negative = true;␊ |
375 | ␉␉␉␉val++;␊ |
376 | ␉␉␉␉size--;␊ |
377 | ␉␉␉}␊ |
378 | ␉␉␉␊ |
379 | ␉␉␉for (sum = 0; size > 0; size--) {␊ |
380 | ␉␉␉␉if (*val < '0' || *val > '9') {␊ |
381 | ␉␉␉␉␉return false;␊ |
382 | ␉␉␉␉}␊ |
383 | ␉␉␉␉␊ |
384 | ␉␉␉␉sum = (sum * 10) + (*val++ - '0');␊ |
385 | ␉␉␉}␊ |
386 | ␉␉␉␊ |
387 | ␉␉␉if (negative) {␊ |
388 | ␉␉␉␉sum = -sum;␊ |
389 | ␉␉␉}␊ |
390 | ␉␉␉*value = sum;␊ |
391 | ␉␉␉return true;␊ |
392 | ␉␉}␊ |
393 | ␉}␊ |
394 | ␉return false;␊ |
395 | }␊ |
396 | ␊ |
397 | /*␊ |
398 | *␊ |
399 | */␊ |
400 | ␊ |
401 | bool getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )␊ |
402 | {␊ |
403 | ␉const char *val;␊ |
404 | ␊ |
405 | ␉int size = 0;␊ |
406 | ␉int sum = 0;␊ |
407 | ␊ |
408 | ␉bool negative = false;␊ |
409 | ␉bool percentage = false;␊ |
410 | ␊ |
411 | ␉if (getValueForKey(key, &val, &size, config)) {␊ |
412 | ␉␉if ( size ) {␊ |
413 | ␉␉␉if (*val == '-') {␊ |
414 | ␉␉␉␉negative = true;␊ |
415 | ␉␉␉␉val++;␊ |
416 | ␉␉␉␉size--;␊ |
417 | ␉␉␉}␊ |
418 | ␊ |
419 | ␉␉␉if (val[size-1] == '%') {␊ |
420 | ␉␉␉␉percentage = true;␊ |
421 | ␉␉␉␉size--;␊ |
422 | ␉␉␉}␊ |
423 | ␊ |
424 | ␉␉␉// convert string to integer␊ |
425 | ␉␉␉for (sum = 0; size > 0; size--) {␊ |
426 | ␉␉␉␉if (*val < '0' || *val > '9') {␊ |
427 | ␉␉␉␉␉return false;␊ |
428 | ␉␉␉␉}␊ |
429 | ␊ |
430 | ␉␉␉␉sum = (sum * 10) + (*val++ - '0');␊ |
431 | ␉␉␉}␊ |
432 | ␊ |
433 | ␉␉␉if (percentage) {␊ |
434 | ␉␉␉␉sum = ( dimension_max * sum ) / 100;␊ |
435 | ␉␉␉}␊ |
436 | ␊ |
437 | ␉␉␉// calculate offset from opposite origin␊ |
438 | ␉␉␉if (negative) {␊ |
439 | ␉␉␉␉sum = ( ( dimension_max - object_size ) - sum );␊ |
440 | ␉␉␉}␊ |
441 | ␊ |
442 | ␉␉} else {␊ |
443 | ␊ |
444 | ␉␉␉// null value calculate center␊ |
445 | ␉␉␉sum = ( dimension_max - object_size ) / 2;␊ |
446 | ␊ |
447 | ␉␉}␊ |
448 | ␊ |
449 | ␉␉*value = (uint16_t) sum;␊ |
450 | ␉␉return true;␊ |
451 | ␉}␊ |
452 | ␊ |
453 | ␉// key not found␊ |
454 | ␉return false;␊ |
455 | }␊ |
456 | ␊ |
457 | /*␊ |
458 | *␉get color value from plist format #RRGGBB␊ |
459 | */␊ |
460 | ␊ |
461 | bool getColorForKey( const char *key, unsigned int *value, config_file_t *config )␊ |
462 | {␊ |
463 | ␉const char *val;␊ |
464 | ␉int size;␊ |
465 | ␊ |
466 | ␉if (getValueForKey(key, &val, &size, config))␊ |
467 | ␉{␊ |
468 | ␉␉if (*val == '#') {␊ |
469 | ␉␉␉val++;␊ |
470 | ␉␉␉*value = strtol(val, NULL, 16);␊ |
471 | ␉␉␉return true;␊ |
472 | ␉␉}␊ |
473 | ␉}␊ |
474 | ␉return false;␊ |
475 | }␊ |
476 | ␊ |
477 | bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config )␊ |
478 | {␊ |
479 | ␉const char *overrideVal;␊ |
480 | ␉int overrideSize;␊ |
481 | ␉bool override, ret;␊ |
482 | ␊ |
483 | ␉if (getValueForBootKey(bootArgs->CommandLine, key, val, size)) {␊ |
484 | ␉␉return true;␊ |
485 | ␉}␊ |
486 | ␊ |
487 | ␉ret = getValueForConfigTableKey(config, key, val, size);␊ |
488 | ␊ |
489 | ␉// Try to find alternate keys in bootInfo->chameleonConfig (if config can be overriden)␊ |
490 | ␉// and prefer its values with the exceptions for␊ |
491 | ␉// "Kernel"="mach_kernel" and "Kernel Flags"="".␊ |
492 | ␊ |
493 | ␉if (config->canOverride) {␊ |
494 | ␉␉if (getValueForConfigTableKey(&bootInfo->chameleonConfig, key, &overrideVal, &overrideSize)) {␊ |
495 | ␉␉␉override = true;␊ |
496 | ␊ |
497 | ␉␉␉// NOTE: Values are defined by apple as being in com.apple.Boot.plist␊ |
498 | ␉␉␉// kHelperRootUUIDKey, kKernelArchKey, kMKextCacheKey, kKernelCacheKey, kKernelNameKey, kKernelFlagsKey␊ |
499 | ␉␉␉if (ret && (strcmp(key, kKernelNameKey) == 0) && (overrideSize == 0)) {␊ |
500 | ␉␉␉␉override = false;␊ |
501 | ␉␉␉}␊ |
502 | ␊ |
503 | ␉␉␉if (ret && (strcmp(key, kKernelFlagsKey) == 0) && (overrideSize == 0)) {␊ |
504 | ␉␉␉␉override = false;␊ |
505 | ␉␉␉}␊ |
506 | ␊ |
507 | ␉␉␉if (override) {␊ |
508 | ␉␉␉␉*val = overrideVal;␊ |
509 | ␉␉␉␉*size = overrideSize;␊ |
510 | ␉␉␉␉ret = true;␊ |
511 | ␉␉␉}␊ |
512 | ␉␉}␊ |
513 | ␉}␊ |
514 | ␉return ret;␊ |
515 | }␊ |
516 | ␊ |
517 | ␊ |
518 | #if UNUSED␊ |
519 | void␊ |
520 | printSystemConfig(char *p1)␊ |
521 | {␊ |
522 | ␉char *p2 = p1, tmp;␊ |
523 | ␊ |
524 | ␉while (*p1 != '\0') {␊ |
525 | ␉␉while (*p2 != '\0' && *p2 != '\n') {␊ |
526 | ␉␉␉p2++;␊ |
527 | ␉␉}␊ |
528 | ␉tmp = *p2;␊ |
529 | ␉*p2 = '\0';␊ |
530 | ␉printf("%s\n", p1);␊ |
531 | ␉*p2 = tmp;␊ |
532 | ␉if (tmp == '\0') {␊ |
533 | ␉␉break;␊ |
534 | ␉}␊ |
535 | ␉p1 = ++p2;␊ |
536 | }␊ |
537 | }␊ |
538 | #endif␊ |
539 | ␊ |
540 | //==========================================================================␊ |
541 | // ParseXMLFile␊ |
542 | // Modifies the input buffer.␊ |
543 | // Expects to see one dictionary in the XML file.␊ |
544 | // Puts the first dictionary it finds in the␊ |
545 | // tag pointer and returns 0, or returns -1 if not found␊ |
546 | // (and does not modify dict pointer).␊ |
547 | // Prints an error message if there is a parsing error.␊ |
548 | //␊ |
549 | int ParseXMLFile( char * buffer, TagPtr * dict )␊ |
550 | {␊ |
551 | ␉long length, pos;␊ |
552 | ␉TagPtr tag;␊ |
553 | ␉pos = 0;␊ |
554 | ␉char *configBuffer;␊ |
555 | ␊ |
556 | ␉configBuffer = malloc(strlen(buffer)+1);␊ |
557 | ␉strcpy(configBuffer, buffer);␊ |
558 | ␊ |
559 | ␉while (1) {␊ |
560 | ␉␉length = XMLParseNextTag(configBuffer + pos, &tag);␊ |
561 | ␉␉␉if (length == -1) {␊ |
562 | ␉␉␉␉break;␊ |
563 | ␉␉␉}␊ |
564 | ␊ |
565 | ␉␉pos += length;␊ |
566 | ␊ |
567 | ␉␉if (tag == 0) {␊ |
568 | ␉␉␉continue;␊ |
569 | ␉␉}␊ |
570 | ␉␉if (tag->type == kTagTypeDict) {␊ |
571 | ␉␉␉break;␊ |
572 | ␉␉}␊ |
573 | ␊ |
574 | ␉␉XMLFreeTag(tag);␊ |
575 | ␉}␊ |
576 | ␉free(configBuffer);␊ |
577 | ␉if (length < 0) {␊ |
578 | ␉␉error ("Error parsing plist file\n");␊ |
579 | ␉␉return -1;␊ |
580 | ␉}␊ |
581 | ␉*dict = tag;␊ |
582 | ␉return 0;␊ |
583 | }␊ |
584 | ␊ |
585 | /* loadConfigFile␊ |
586 | *␊ |
587 | * Returns 0 - successful.␊ |
588 | *␉␉ -1 - unsuccesful.␊ |
589 | */␊ |
590 | int loadConfigFile (const char *configFile, config_file_t *config)␊ |
591 | {␊ |
592 | ␉int fd, count;␊ |
593 | ␊ |
594 | ␉if ((fd = open_bvdev("bt(0,0)", configFile, 0)) < 0) {␊ |
595 | ␉␉return -1;␊ |
596 | ␉}␊ |
597 | ␉// read file␊ |
598 | ␉count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);␊ |
599 | ␉close(fd);␊ |
600 | ␊ |
601 | ␉// build xml dictionary␊ |
602 | ␉ParseXMLFile(config->plist, &config->dictionary);␊ |
603 | ␉return 0;␊ |
604 | }␊ |
605 | ␊ |
606 | ␊ |
607 | /* loadSystemConfig␊ |
608 | *␊ |
609 | * Returns 0 - successful.␊ |
610 | *␉␉ -1 - unsuccesful.␊ |
611 | */␊ |
612 | int loadSystemConfig(config_file_t *config)␊ |
613 | {␊ |
614 | ␉char *dirspec[] = {␊ |
615 | ␉␉"/OS X Install Data/com.apple.Boot.plist",␊ |
616 | ␉␉"/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",␊ |
617 | ␉};␊ |
618 | ␊ |
619 | ␉int i, fd, count, ret=-1;␊ |
620 | ␊ |
621 | ␉for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++) {␊ |
622 | ␉␉if ((fd = open(dirspec[i], 0)) >= 0) {␊ |
623 | ␉␉␉// read file␊ |
624 | ␉␉␉count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);␊ |
625 | ␉␉␉close(fd);␊ |
626 | ␊ |
627 | ␉␉␉// build xml dictionary␊ |
628 | ␉␉␉ParseXMLFile(config->plist, &config->dictionary);␊ |
629 | ␉␉␉sysConfigValid = true;␉␊ |
630 | ␉␉␉ret=0;␊ |
631 | ␊ |
632 | ␉␉␉break;␊ |
633 | ␉␉}␊ |
634 | ␉}␊ |
635 | ␊ |
636 | ␉if(ret == -1) ret = loadHelperConfig(config);␊ |
637 | ␊ |
638 | ␉// Always enable canOverride flag (for SystemConfig)␊ |
639 | ␉config->canOverride = true;␊ |
640 | ␊ |
641 | ␉return ret;␊ |
642 | }␊ |
643 | ␊ |
644 | /* loadChameleonConfig␊ |
645 | *␊ |
646 | * Returns 0 - successful.␊ |
647 | *␉␉ -1 - unsuccesful.␊ |
648 | */␊ |
649 | int loadChameleonConfig(config_file_t *config, BVRef chain)␊ |
650 | {␊ |
651 | ␉char *dirspec[] = {␊ |
652 | ␉␉"/Extra/org.chameleon.Boot.plist",␊ |
653 | ␉␉"/Extra/com.apple.Boot.plist", /* DEPRECIATED */␊ |
654 | ␉};␊ |
655 | ␊ |
656 | ␉int i;␊ |
657 | ␊ |
658 | ␉for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++) {␊ |
659 | ␉␉if ( loadChameleonConfigForDevice(config, "rd(0,0)", dirspec[i]) == 0 ) {␊ |
660 | ␉␉␉return 0;␊ |
661 | ␉␉}␊ |
662 | ␉␉if ( loadChameleonConfigForDevice(config, "", dirspec[i]) == 0 ) {␊ |
663 | ␉␉␉return 0;␊ |
664 | ␉␉}␊ |
665 | ␉␉if ( loadChameleonConfigForDevice(config, "bt(0,0)", dirspec[i]) == 0 ) {␊ |
666 | ␉␉␉return 0;␊ |
667 | ␉␉}␊ |
668 | ␉␉BVRef bvr;␊ |
669 | ␉␉for ( bvr = chain; bvr; bvr = bvr->next ) { /* C99 Error */␊ |
670 | ␉␉␉char device[256];␊ |
671 | ␉␉␉getDeviceDescription(bvr, device);␊ |
672 | ␊ |
673 | ␉␉␉if ( loadChameleonConfigForDevice(config, device, dirspec[i]) == 0 ) {␊ |
674 | ␉␉␉␉return 0;␊ |
675 | ␉␉␉}␊ |
676 | ␉␉}␊ |
677 | ␉}␊ |
678 | ␉return -1;␊ |
679 | }␊ |
680 | ␊ |
681 | /* loadChameleonConfigForDevice␊ |
682 | *␊ |
683 | * Returns 0 - successful.␊ |
684 | *␉␉ -1 - unsuccesful.␊ |
685 | */␊ |
686 | int loadChameleonConfigForDevice(config_file_t *config, const char *device, const char *path)␊ |
687 | {␊ |
688 | ␉char full_path[1024];␊ |
689 | ␉int fd;␊ |
690 | ␊ |
691 | ␉snprintf(full_path, sizeof(full_path), "%s%s", device, path);␊ |
692 | ␊ |
693 | ␉if ((fd = open(full_path, 0)) >= 0) {␊ |
694 | ␉␉// Check for depreciated file names and annoy the user about it.␊ |
695 | ␉␉if(strstr(full_path, "com.apple.Boot.plist")) {␊ |
696 | ␉␉␉printf("%s is depreciated.\n", full_path);␊ |
697 | ␉␉␉full_path[strlen(full_path) - strlen("com.apple.Boot.plist")] = 0;␊ |
698 | ␉␉␉printf("Please use the file %sorg.chameleon.Boot.plist instead.\n", full_path);␊ |
699 | ␉␉␉pause();␊ |
700 | ␉␉}␊ |
701 | ␉␉// read file␊ |
702 | ␉␉read(fd, config->plist, IO_CONFIG_DATA_SIZE);␊ |
703 | ␉␉close(fd);␊ |
704 | ␊ |
705 | ␉␉// build xml dictionary␊ |
706 | ␉␉ParseXMLFile(config->plist, &config->dictionary);␊ |
707 | ␉␉sysConfigValid = true;␊ |
708 | ␉␉return 0;␊ |
709 | ␉}␊ |
710 | ␉return -1;␊ |
711 | }␊ |
712 | ␊ |
713 | /* loadHelperConfig␊ |
714 | *␊ |
715 | * Returns 0 - successful.␊ |
716 | *␉␉ -1 - unsuccesful.␊ |
717 | */␊ |
718 | int loadHelperConfig(config_file_t *config)␊ |
719 | {␊ |
720 | ␉char *dirspec[] = {␊ |
721 | ␉␉"/com.apple.boot.P/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",␊ |
722 | ␉␉"/com.apple.boot.R/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",␊ |
723 | ␉␉"/com.apple.boot.S/Library/Preferences/SystemConfiguration/com.apple.Boot.plist"␊ |
724 | ␉};␊ |
725 | ␊ |
726 | ␉int i, fd, count, ret=-1;␊ |
727 | ␊ |
728 | ␉for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++) {␊ |
729 | ␉␉if ((fd = open(dirspec[i], 0)) >= 0) {␊ |
730 | ␉␉␉// read file␊ |
731 | ␉␉␉count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);␊ |
732 | ␉␉␉close(fd);␊ |
733 | ␉␉␉␊ |
734 | ␉␉␉// build xml dictionary␊ |
735 | ␉␉␉ParseXMLFile(config->plist, &config->dictionary);␊ |
736 | ␉␉␉sysConfigValid = true;␉␊ |
737 | ␉␉␉ret=0;␊ |
738 | ␉␉␉break;␊ |
739 | ␉␉}␊ |
740 | ␉}␊ |
741 | ␉return ret;␊ |
742 | }␊ |
743 | ␊ |
744 | char * newString(const char * oldString)␊ |
745 | {␊ |
746 | ␉if ( oldString ) {␊ |
747 | ␉␉return strcpy(malloc(strlen(oldString)+1), oldString);␊ |
748 | ␉} else {␊ |
749 | ␉␉return NULL;␊ |
750 | ␉}␊ |
751 | }␊ |
752 | ␊ |
753 | /*␊ |
754 | * Extracts the next argument from the command line, double quotes are allowed here.␊ |
755 | */␊ |
756 | char * getNextArg(char ** argPtr, char * val)␊ |
757 | {␊ |
758 | ␉char * ptr = *argPtr;␊ |
759 | ␉const char * strStart;␊ |
760 | ␉int len = 0;␊ |
761 | ␉bool isQuoted = false;␊ |
762 | ␊ |
763 | ␉*val = '\0';␊ |
764 | ␊ |
765 | ␉// Scan for the next non-whitespace character.␊ |
766 | ␉while ( *ptr && (*ptr == ' ' || *ptr == '=') ) {␊ |
767 | ␉␉ptr++;␊ |
768 | ␉}␊ |
769 | ␊ |
770 | ␉strStart = ptr;␊ |
771 | ␊ |
772 | ␉// Skip the leading double quote character.␊ |
773 | ␉if (*ptr == '\"') {␊ |
774 | ␉␉isQuoted = true;␊ |
775 | ␉␉ptr++;␊ |
776 | ␉␉strStart++;␊ |
777 | ␉}␊ |
778 | ␊ |
779 | ␉// Scan for the argument terminator character.␊ |
780 | ␉// This can be either a NULL character - in case we reach the end of the string,␊ |
781 | ␉// a double quote in case of quoted argument,␊ |
782 | ␉// or a whitespace character (' ' or '=') for non-quoted argument.␊ |
783 | ␉while (*ptr && !( (isQuoted && (*ptr == '\"')) ||␊ |
784 | (!isQuoted && (*ptr == ' ' || *ptr == '=')) )␊ |
785 | ) {␊ |
786 | ␉␉ptr++;␊ |
787 | ␉}␊ |
788 | ␊ |
789 | ␉len = ptr - strStart;␊ |
790 | ␊ |
791 | ␉// Skip the closing double quote character and adjust␊ |
792 | ␉// the starting pointer for the next getNextArg call.␊ |
793 | ␉if (*ptr && isQuoted && *ptr == '\"') {␊ |
794 | ␉␉ptr++;␊ |
795 | ␉}␊ |
796 | ␊ |
797 | ␉// Copy the extracted argument to val.␊ |
798 | ␉strncat(val, strStart, len);␊ |
799 | ␊ |
800 | ␉// Set command line pointer.␊ |
801 | ␉*argPtr = ptr;␊ |
802 | ␊ |
803 | ␉return ptr;␊ |
804 | }␊ |
805 | |