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 | /*␊ |
42 | * Compare a string to a key with quoted characters␊ |
43 | */␊ |
44 | static inline int␊ |
45 | keyncmp(const char *str, const char *key, int n)␊ |
46 | {␊ |
47 | int c;␊ |
48 | while (n--) {␊ |
49 | ␉c = *key++;␊ |
50 | ␉if (c == '\\') {␊ |
51 | ␉ switch(c = *key++) {␊ |
52 | ␉ case 'n':␊ |
53 | ␉␉c = '\n';␊ |
54 | ␉␉break;␊ |
55 | ␉ case 'r':␊ |
56 | ␉␉c = '\r';␊ |
57 | ␉␉break;␊ |
58 | ␉ case 't':␊ |
59 | ␉␉c = '\t';␊ |
60 | ␉␉break;␊ |
61 | ␉ default:␊ |
62 | ␉␉break;␊ |
63 | ␉ }␊ |
64 | ␉} else if (c == '\"') {␊ |
65 | ␉ // Premature end of key␊ |
66 | ␉ return 1;␊ |
67 | ␉}␊ |
68 | ␉if (c != *str++) {␊ |
69 | ␉ return 1;␊ |
70 | ␉}␊ |
71 | }␊ |
72 | return 0;␊ |
73 | }␊ |
74 | ␊ |
75 | static void eatThru(char val, const char **table_p)␊ |
76 | {␊ |
77 | ␉register const char *table = *table_p;␊ |
78 | ␉register bool found = false;␊ |
79 | ␊ |
80 | ␉while (*table && !found)␊ |
81 | ␉{␊ |
82 | ␉␉if (*table == '\\') table += 2;␊ |
83 | ␉␉else␊ |
84 | ␉␉{␊ |
85 | ␉␉␉if (*table == val) found = true;␊ |
86 | ␉␉␉table++;␊ |
87 | ␉␉}␊ |
88 | ␉}␊ |
89 | ␉*table_p = table;␊ |
90 | }␊ |
91 | ␊ |
92 | /* Remove key and its associated value from the table. */␊ |
93 | ␊ |
94 | bool␊ |
95 | removeKeyFromTable(const char *key, char *table)␊ |
96 | {␊ |
97 | register int len;␊ |
98 | register char *tab;␊ |
99 | char *buf;␊ |
100 | ␊ |
101 | len = strlen(key);␊ |
102 | tab = (char *)table;␊ |
103 | buf = (char *)malloc(len + 3);␊ |
104 | ␊ |
105 | snprintf(buf, len + 3,"\"%s\"", key);␊ |
106 | len = strlen(buf);␊ |
107 | ␊ |
108 | while(*tab) {␊ |
109 | if(strncmp(buf, tab, len) == 0) {␊ |
110 | char c;␊ |
111 | ␊ |
112 | while((c = *(tab + len)) != ';') {␊ |
113 | if(c == 0) {␊ |
114 | len = -1;␊ |
115 | goto out;␊ |
116 | }␊ |
117 | len++;␊ |
118 | }␊ |
119 | len++;␊ |
120 | if(*(tab + len) == '\n') len++;␊ |
121 | goto out;␊ |
122 | }␊ |
123 | tab++;␊ |
124 | }␊ |
125 | len = -1;␊ |
126 | out:␊ |
127 | free(buf);␊ |
128 | ␊ |
129 | if(len == -1) return false;␊ |
130 | ␊ |
131 | while((*tab = *(tab + len))) {␊ |
132 | tab++;␊ |
133 | }␊ |
134 | ␊ |
135 | return true;␊ |
136 | }␊ |
137 | ␊ |
138 | char *newStringFromList(char **list, int *size)␊ |
139 | {␊ |
140 | ␉char *begin = *list, *end;␊ |
141 | ␉char *newstr;␊ |
142 | ␉int newsize = *size;␊ |
143 | ␉int bufsize;␊ |
144 | ␊ |
145 | ␉while (*begin && newsize && isspace(*begin)) {␊ |
146 | ␉␉begin++;␊ |
147 | ␉␉newsize--;␊ |
148 | ␉}␊ |
149 | ␉end = begin;␊ |
150 | ␉while (*end && newsize && !isspace(*end)) {␊ |
151 | ␉␉end++;␊ |
152 | ␉␉newsize--;␊ |
153 | ␉}␊ |
154 | ␉if (begin == end) {␊ |
155 | ␉␉return 0;␊ |
156 | ␉}␊ |
157 | ␉bufsize = end - begin + 1;␊ |
158 | ␉newstr = malloc(bufsize);␊ |
159 | ␉if (!newstr)␊ |
160 | ␉{␊ |
161 | ␉␉return 0;␊ |
162 | ␉}␊ |
163 | ␉strlcpy(newstr, begin, bufsize);␊ |
164 | ␉*list = end;␊ |
165 | ␉*size = newsize;␊ |
166 | ␉return newstr;␊ |
167 | }␊ |
168 | ␊ |
169 | #endif␊ |
170 | ␊ |
171 | /* ␊ |
172 | * compress == compress escaped characters to one character␊ |
173 | */␊ |
174 | int stringLength(const char *table, int compress)␊ |
175 | {␊ |
176 | ␉int ret = 0;␊ |
177 | ␊ |
178 | ␉while (*table) {␊ |
179 | ␉␉if (*table == '\\') {␊ |
180 | ␉␉␉table += 2;␊ |
181 | ␉␉␉ret += 1 + (compress ? 0 : 1);␊ |
182 | ␉␉}␊ |
183 | ␉␉else␊ |
184 | ␉␉{␊ |
185 | ␉␉␉if (*table == '\"')␊ |
186 | ␉␉␉{␊ |
187 | ␉␉␉␉return ret;␊ |
188 | ␉␉␉}␊ |
189 | ␉␉␉ret++;␊ |
190 | ␉␉␉table++;␊ |
191 | ␉␉}␊ |
192 | ␉}␊ |
193 | ␉return ret;␊ |
194 | }␊ |
195 | ␊ |
196 | ␊ |
197 | bool getValueForConfigTableKey(config_file_t *config, const char *key, const char **val, int *size)␊ |
198 | {␊ |
199 | ␉if (config->dictionary != 0 ) {␊ |
200 | ␉␉// Look up key in XML dictionary␊ |
201 | ␉␉TagPtr value;␊ |
202 | ␉␉value = XMLGetProperty(config->dictionary, key);␊ |
203 | ␉␉if (value != 0) {␊ |
204 | ␉␉␉if (value->type != kTagTypeString) {␊ |
205 | ␉␉␉␉error("Non-string tag '%s' found in config file\n", key);␊ |
206 | ␉␉␉␉return false;␊ |
207 | ␉␉␉}␊ |
208 | ␉␉␉*val = value->string;␊ |
209 | ␉␉␉*size = strlen(value->string);␊ |
210 | ␉␉␉return true;␊ |
211 | ␉␉}␊ |
212 | ␉} else {␊ |
213 | ␊ |
214 | ␉␉// Legacy plist-style table␊ |
215 | ␊ |
216 | ␉}␊ |
217 | ␊ |
218 | ␉return false;␊ |
219 | }␊ |
220 | ␊ |
221 | #if UNUSED␊ |
222 | ␊ |
223 | /*␊ |
224 | * Returns a new malloc'ed string if one is found␊ |
225 | * in the string table matching 'key'. Also translates␊ |
226 | * \n escapes in the string.␊ |
227 | */␊ |
228 | char *newStringForStringTableKey(char *table, char *key, config_file_t *config)␊ |
229 | {␊ |
230 | ␉const char *val;␊ |
231 | ␉char *newstr, *p;␊ |
232 | ␉int size;␊ |
233 | ␊ |
234 | ␉if (getValueForConfigTableKey(config, key, &val, &size))␊ |
235 | ␉{␊ |
236 | ␉␉newstr = (char *)malloc(size+1);␊ |
237 | ␉␉if (!newstr)␊ |
238 | ␉␉{␊ |
239 | ␉␉␉return 0;␊ |
240 | ␉␉}␊ |
241 | ␉␉for (p = newstr; size; size--, p++, val++) {␊ |
242 | ␉␉␉if ((*p = *val) == '\\') {␊ |
243 | ␉␉␉␉switch (*++val) {␊ |
244 | ␉␉␉␉␉case 'r':␊ |
245 | ␉␉␉␉␉␉*p = '\r';␊ |
246 | ␉␉␉␉␉break;␊ |
247 | ␉␉␉␉␉case 'n':␊ |
248 | ␉␉␉␉␉␉*p = '\n';␊ |
249 | ␉␉␉␉␉break;␊ |
250 | ␉␉␉␉␉case 't':␊ |
251 | ␉␉␉␉␉␉*p = '\t';␊ |
252 | ␉␉␉␉␉break;␊ |
253 | ␉␉␉␉␉default:␊ |
254 | ␉␉␉␉␉␉*p = *val;␊ |
255 | ␉␉␉␉␉break;␊ |
256 | ␉␉␉␉}␊ |
257 | ␉␉␉␉size--;␊ |
258 | ␉␉␉}␊ |
259 | ␉␉}␊ |
260 | ␉␉*p = '\0';␊ |
261 | ␉␉return newstr;␊ |
262 | ␉} else {␊ |
263 | ␉␉return 0;␊ |
264 | ␉}␊ |
265 | }␊ |
266 | ␊ |
267 | #endif␊ |
268 | ␊ |
269 | char *␊ |
270 | newStringForKey(char *key, config_file_t *config)␊ |
271 | {␊ |
272 | ␉const char *val;␊ |
273 | ␉char *newstr;␊ |
274 | ␉int size;␊ |
275 | ␊ |
276 | ␉if (getValueForKey(key, &val, &size, config) && size) {␊ |
277 | ␉␉newstr = (char *)malloc(size + 1);␊ |
278 | ␉␉if (!newstr)␊ |
279 | ␉␉{␊ |
280 | ␉␉␉return 0;␊ |
281 | ␉␉}␊ |
282 | ␉␉strlcpy(newstr, val, size + 1);␊ |
283 | ␉␉return newstr;␊ |
284 | ␉} else {␊ |
285 | ␉␉return 0;␊ |
286 | ␉}␊ |
287 | }␊ |
288 | ␊ |
289 | /* parse a command line␊ |
290 | * in the form: [<argument> ...] [<option>=<value> ...]␊ |
291 | * both <option> and <value> must be either composed of␊ |
292 | * non-whitespace characters, or enclosed in quotes.␊ |
293 | */␊ |
294 | ␊ |
295 | static const char *getToken(const char *line, const char **begin, int *len)␊ |
296 | {␊ |
297 | ␉if (*line == '\"') {␊ |
298 | ␉␉*begin = ++line;␊ |
299 | ␉␉while (*line && *line != '\"') {␊ |
300 | ␉␉␉line++;␊ |
301 | ␉␉}␊ |
302 | ␉␉*len = line++ - *begin;␊ |
303 | ␉} else {␊ |
304 | ␉␉*begin = line;␊ |
305 | ␉␉while (*line && !isspace(*line) && *line != '=') {␊ |
306 | ␉␉␉line++;␊ |
307 | ␉␉}␊ |
308 | ␉␉*len = line - *begin;␊ |
309 | ␉}␊ |
310 | ␉return line;␊ |
311 | }␊ |
312 | ␊ |
313 | bool getValueForBootKey(const char *line, const char *match, const char **matchval, int *len)␊ |
314 | {␊ |
315 | ␉const char *key, *value;␊ |
316 | ␉int key_len, value_len;␊ |
317 | ␉bool retval = false;␊ |
318 | ␊ |
319 | ␉while (*line) {␊ |
320 | ␉␉/* look for keyword or argument */␊ |
321 | ␉␉while (isspace(*line))␊ |
322 | ␉␉{␊ |
323 | ␉␉␉line++;␊ |
324 | ␉␉}␊ |
325 | ␊ |
326 | ␉␉/* now look for '=' or whitespace */␊ |
327 | ␉␉line = getToken(line, &key, &key_len);␊ |
328 | ␉␉/* line now points to '=' or space */␊ |
329 | ␉␉if (*line && !isspace(*line)) {␊ |
330 | ␉␉␉line = getToken(++line, &value, &value_len);␊ |
331 | ␉␉} else {␊ |
332 | ␉␉␉value = line;␊ |
333 | ␉␉␉value_len = 0;␊ |
334 | ␉␉}␊ |
335 | ␉␉if ((strlen(match) == key_len) && strncmp(match, key, key_len) == 0)␊ |
336 | ␉␉{␊ |
337 | ␉␉␉// create a new string␊ |
338 | ␉␉␉char* newstr = malloc(value_len + 1);␊ |
339 | ␉␉␉strncpy(newstr, value, value_len);␊ |
340 | ␉␉␉newstr[value_len] = 0;␊ |
341 | ␊ |
342 | ␉␉␉*matchval = newstr;␊ |
343 | ␉␉␉*len = value_len;␊ |
344 | ␉␉␉retval = true;␊ |
345 | ␉␉␉/* Continue to look for this key; last one wins. */␊ |
346 | ␉␉}␊ |
347 | ␉}␊ |
348 | ␊ |
349 | ␉return retval;␊ |
350 | }␊ |
351 | ␊ |
352 | /* Return NULL if no option has been successfully retrieved, or the string otherwise */␊ |
353 | const char *getStringForKey(const char *key, config_file_t *config)␊ |
354 | {␊ |
355 | ␉static const char *value = 0;␊ |
356 | ␉int len = 0;␊ |
357 | ␉if (!getValueForKey(key, &value, &len, config))␊ |
358 | ␉{␊ |
359 | ␉␉value = 0;␊ |
360 | ␉}␊ |
361 | ␉return value;␊ |
362 | }␊ |
363 | ␊ |
364 | ␊ |
365 | /* Returns TRUE if a value was found, FALSE otherwise.␊ |
366 | * The boolean value of the key is stored in 'val'.␊ |
367 | */␊ |
368 | ␊ |
369 | bool getBoolForKey(const char *key, bool *result_val, config_file_t *config)␊ |
370 | {␊ |
371 | const char *key_val;␊ |
372 | int size;␊ |
373 | ␊ |
374 | ␉if (getValueForKey(key, &key_val, &size, config))␊ |
375 | ␉{␊ |
376 | ␉␉if ((size >= 1) && (key_val[0] == 'Y' || key_val[0] == 'y'))␊ |
377 | ␉␉{␊ |
378 | ␉␉␉*result_val = true;␊ |
379 | ␉␉}␊ |
380 | ␉␉else␊ |
381 | ␉␉{␊ |
382 | ␉␉␉*result_val = false;␊ |
383 | ␉␉}␊ |
384 | ␉␉return true;␊ |
385 | ␉}␊ |
386 | ␉return false;␊ |
387 | }␊ |
388 | ␊ |
389 | bool getIntForKey(const char *key, int *value, config_file_t *config)␊ |
390 | {␊ |
391 | ␉const char *val;␊ |
392 | ␉int size, sum;␊ |
393 | ␉bool negative = false;␊ |
394 | ␊ |
395 | ␉if (getValueForKey(key, &val, &size, config))␊ |
396 | ␉{␊ |
397 | ␉␉if (size)␊ |
398 | ␉␉{␊ |
399 | ␉␉␉if (*val == '-')␊ |
400 | ␉␉␉{␊ |
401 | ␉␉␉␉negative = true;␊ |
402 | ␉␉␉␉val++;␊ |
403 | ␉␉␉␉size--;␊ |
404 | ␉␉␉}␊ |
405 | ␉␉␉␊ |
406 | ␉␉␉for (sum = 0; size > 0; size--)␊ |
407 | ␉␉␉{␊ |
408 | ␉␉␉␉if (*val < '0' || *val > '9')␊ |
409 | ␉␉␉␉{␊ |
410 | ␉␉␉␉␉return false;␊ |
411 | ␉␉␉␉}␊ |
412 | ␉␉␉␉␊ |
413 | ␉␉␉␉sum = (sum * 10) + (*val++ - '0');␊ |
414 | ␉␉␉}␊ |
415 | ␉␉␉␊ |
416 | ␉␉␉if (negative)␊ |
417 | ␉␉␉{␊ |
418 | ␉␉␉␉sum = -sum;␊ |
419 | ␉␉␉}␊ |
420 | ␉␉␉*value = sum;␊ |
421 | ␉␉␉return true;␊ |
422 | ␉␉}␊ |
423 | ␉}␊ |
424 | ␉return false;␊ |
425 | }␊ |
426 | /*␊ |
427 | *␊ |
428 | */␊ |
429 | ␊ |
430 | bool getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )␊ |
431 | {␊ |
432 | ␉const char *val;␊ |
433 | ␊ |
434 | ␉int size = 0;␊ |
435 | ␉int sum = 0;␊ |
436 | ␊ |
437 | ␉bool negative = false;␊ |
438 | ␉bool percentage = false;␊ |
439 | ␊ |
440 | ␉if (getValueForKey(key, &val, &size, config))␊ |
441 | ␉{␊ |
442 | ␉␉if ( size )␊ |
443 | ␉␉{␊ |
444 | ␉␉␉if (*val == '-')␊ |
445 | ␉␉␉{␊ |
446 | ␉␉␉␉negative = true;␊ |
447 | ␉␉␉␉val++;␊ |
448 | ␉␉␉␉size--;␊ |
449 | ␉␉␉}␊ |
450 | ␊ |
451 | ␉␉␉if (val[size-1] == '%')␊ |
452 | ␉␉␉{␊ |
453 | ␉␉␉␉percentage = true;␊ |
454 | ␉␉␉␉size--;␊ |
455 | ␉␉␉}␊ |
456 | ␊ |
457 | ␉␉␉// convert string to integer␊ |
458 | ␉␉␉for (sum = 0; size > 0; size--)␊ |
459 | ␉␉␉{␊ |
460 | ␉␉␉␉if (*val < '0' || *val > '9')␊ |
461 | ␉␉␉␉{␊ |
462 | ␉␉␉␉␉return false;␊ |
463 | ␉␉␉␉}␊ |
464 | ␊ |
465 | ␉␉␉␉sum = (sum * 10) + (*val++ - '0');␊ |
466 | ␉␉␉}␊ |
467 | ␊ |
468 | ␉␉␉if (percentage)␊ |
469 | ␉␉␉{␊ |
470 | ␉␉␉␉sum = ( dimension_max * sum ) / 100;␊ |
471 | ␉␉␉}␊ |
472 | ␊ |
473 | ␉␉␉// calculate offset from opposite origin␊ |
474 | ␉␉␉if (negative)␊ |
475 | ␉␉␉{␊ |
476 | ␉␉␉␉sum = ( ( dimension_max - object_size ) - sum );␊ |
477 | ␉␉␉}␊ |
478 | ␊ |
479 | ␉␉}␊ |
480 | ␉␉else␊ |
481 | ␉␉{␊ |
482 | ␊ |
483 | ␉␉␉// null value calculate center␊ |
484 | ␉␉␉sum = ( dimension_max - object_size ) / 2;␊ |
485 | ␊ |
486 | ␉␉}␊ |
487 | ␊ |
488 | ␉␉*value = (uint16_t) sum;␊ |
489 | ␉␉return true;␊ |
490 | ␉}␊ |
491 | ␊ |
492 | ␉// key not found␊ |
493 | ␉return false;␊ |
494 | }␊ |
495 | ␊ |
496 | /*␊ |
497 | *␉get color value from plist format #RRGGBB␊ |
498 | */␊ |
499 | ␊ |
500 | bool getColorForKey( const char *key, unsigned int *value, config_file_t *config )␊ |
501 | {␊ |
502 | ␉const char *val;␊ |
503 | ␉int size;␊ |
504 | ␊ |
505 | ␉if (getValueForKey(key, &val, &size, config))␊ |
506 | ␉{␊ |
507 | ␉␉if (*val == '#') {␊ |
508 | ␉␉␉val++;␊ |
509 | ␉␉␉*value = strtol(val, NULL, 16);␊ |
510 | ␉␉␉return true;␊ |
511 | ␉␉}␊ |
512 | ␉}␊ |
513 | ␉return false;␊ |
514 | }␊ |
515 | ␊ |
516 | bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config )␊ |
517 | {␊ |
518 | ␉const char *overrideVal;␊ |
519 | ␉int overrideSize;␊ |
520 | ␉bool override, ret;␊ |
521 | ␊ |
522 | ␉if (getValueForBootKey(bootArgs->CommandLine, key, val, size))␊ |
523 | ␉{␊ |
524 | ␉␉return true;␊ |
525 | ␉}␊ |
526 | ␊ |
527 | ␉ret = getValueForConfigTableKey(config, key, val, size);␊ |
528 | ␊ |
529 | ␉// Try to find alternate keys in bootInfo->chameleonConfig (if config can be overriden)␊ |
530 | ␉// and prefer its values with the exceptions for␊ |
531 | ␉// "Kernel"="mach_kernel" and "Kernel Flags"="".␊ |
532 | ␊ |
533 | ␉if (config->canOverride)␊ |
534 | ␉{␊ |
535 | ␉␉if (getValueForConfigTableKey(&bootInfo->chameleonConfig, key, &overrideVal, &overrideSize))␊ |
536 | ␉␉{␊ |
537 | ␉␉␉override = true;␊ |
538 | ␊ |
539 | ␉␉␉// NOTE: Values are defined by apple as being in com.apple.Boot.plist␊ |
540 | ␉␉␉// kHelperRootUUIDKey, kKernelArchKey, kMKextCacheKey, kKernelCacheKey, kKernelNameKey, kKernelFlagsKey␊ |
541 | ␉␉␉if (ret && (strcmp(key, kKernelNameKey) == 0) && (overrideSize == 0))␊ |
542 | ␉␉␉{␊ |
543 | ␉␉␉␉override = false;␊ |
544 | ␉␉␉}␊ |
545 | ␊ |
546 | ␉␉␉if (ret && (strcmp(key, kKernelFlagsKey) == 0) && (overrideSize == 0))␊ |
547 | ␉␉␉{␊ |
548 | ␉␉␉␉override = false;␊ |
549 | ␉␉␉}␊ |
550 | ␊ |
551 | ␉␉␉if (override)␊ |
552 | ␉␉␉{␊ |
553 | ␉␉␉␉*val = overrideVal;␊ |
554 | ␉␉␉␉*size = overrideSize;␊ |
555 | ␉␉␉␉ret = true;␊ |
556 | ␉␉␉}␊ |
557 | ␉␉}␊ |
558 | ␉}␊ |
559 | ␉return ret;␊ |
560 | }␊ |
561 | ␊ |
562 | ␊ |
563 | #if UNUSED␊ |
564 | void␊ |
565 | printSystemConfig(char *p1)␊ |
566 | {␊ |
567 | ␉char *p2 = p1, tmp;␊ |
568 | ␊ |
569 | ␉while (*p1 != '\0')␊ |
570 | ␉{␊ |
571 | ␉␉while (*p2 != '\0' && *p2 != '\n')␊ |
572 | ␉␉{␊ |
573 | ␉␉␉p2++;␊ |
574 | ␉␉}␊ |
575 | ␉tmp = *p2;␊ |
576 | ␉*p2 = '\0';␊ |
577 | ␉printf("%s\n", p1);␊ |
578 | ␉*p2 = tmp;␊ |
579 | ␉if (tmp == '\0')␊ |
580 | ␉{␊ |
581 | ␉␉break;␊ |
582 | ␉}␊ |
583 | ␉p1 = ++p2;␊ |
584 | }␊ |
585 | }␊ |
586 | #endif␊ |
587 | ␊ |
588 | //==========================================================================␊ |
589 | // ParseXMLFile␊ |
590 | // Modifies the input buffer.␊ |
591 | // Expects to see one dictionary in the XML file.␊ |
592 | // Puts the first dictionary it finds in the␊ |
593 | // tag pointer and returns 0, or returns -1 if not found␊ |
594 | // (and does not modify dict pointer).␊ |
595 | // Prints an error message if there is a parsing error.␊ |
596 | //␊ |
597 | int ParseXMLFile( char *buffer, TagPtr *dict )␊ |
598 | {␊ |
599 | ␉long length, pos;␊ |
600 | ␉TagPtr tag = 0;␊ |
601 | ␉pos = 0;␊ |
602 | ␉char *configBuffer;␊ |
603 | ␊ |
604 | ␉length = strlen(buffer) + 1;␊ |
605 | ␊ |
606 | ␉configBuffer = malloc(strlen(buffer)+1);␊ |
607 | ␉if (!configBuffer)␊ |
608 | ␉{␊ |
609 | ␉␉return -1;␊ |
610 | ␉}␊ |
611 | ␉strlcpy(configBuffer, buffer, length );␊ |
612 | ␊ |
613 | ␉while (1)␊ |
614 | ␉{␊ |
615 | ␉␉length = XMLParseNextTag(configBuffer + pos, &tag);␊ |
616 | ␉␉␉if (length == -1)␊ |
617 | ␉␉␉{␊ |
618 | ␉␉␉␉break;␊ |
619 | ␉␉␉}␊ |
620 | ␊ |
621 | ␉␉pos += length;␊ |
622 | ␊ |
623 | ␉␉if (tag == 0)␊ |
624 | ␉␉{␊ |
625 | ␉␉␉continue;␊ |
626 | ␉␉}␊ |
627 | ␉␉if (tag->type == kTagTypeDict)␊ |
628 | ␉␉{␊ |
629 | ␉␉␉break;␊ |
630 | ␉␉}␊ |
631 | ␊ |
632 | ␉␉XMLFreeTag(tag);␊ |
633 | ␉}␊ |
634 | ␉free(configBuffer);␊ |
635 | ␉if (length < 0) {␊ |
636 | ␉␉error ("Error parsing plist file\n");␊ |
637 | ␉␉return -1;␊ |
638 | ␉}␊ |
639 | ␉*dict = tag;␊ |
640 | ␉return 0;␊ |
641 | }␊ |
642 | ␊ |
643 | /* loadConfigFile␊ |
644 | *␊ |
645 | * Returns 0 - successful.␊ |
646 | *␉␉ -1 - unsuccesful.␊ |
647 | */␊ |
648 | int loadConfigFile (const char *configFile, config_file_t *config)␊ |
649 | {␊ |
650 | ␉int fd, count;␊ |
651 | ␊ |
652 | ␉if ((fd = open_bvdev("bt(0,0)", configFile, 0)) < 0)␊ |
653 | ␉{␊ |
654 | ␉␉return -1;␊ |
655 | ␉}␊ |
656 | ␉// read file␊ |
657 | ␉count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);␊ |
658 | ␉close(fd);␊ |
659 | ␊ |
660 | ␉// build xml dictionary␊ |
661 | ␉ParseXMLFile(config->plist, &config->dictionary);␊ |
662 | ␉return 0;␊ |
663 | }␊ |
664 | ␊ |
665 | ␊ |
666 | /* loadSystemConfig␊ |
667 | *␊ |
668 | * Returns 0 - successful.␊ |
669 | *␉␉ -1 - unsuccesful.␊ |
670 | */␊ |
671 | int loadSystemConfig(config_file_t *config)␊ |
672 | {␊ |
673 | ␉char *dirspec[] = {␊ |
674 | ␉␉"/com.apple.recovery.boot/com.apple.Boot.plist",␉␉␉// OS X Recovery␊ |
675 | ␉␉"/OS X Install Data/com.apple.Boot.plist",␉␉␉␉// OS X Installer (10.8+)␊ |
676 | ␉␉"/Mac OS X Install Data/com.apple.Boot.plist",␉␉␉␉// OS X Installer (Lion 10.7)␊ |
677 | ␉␉//"/.IABootFiles/com.apple.Boot.plist",␉␉␉␉␉// OS X Installer␊ |
678 | ␉␉"/Library/Preferences/SystemConfiguration/com.apple.Boot.plist"␉␉// com.apple.Boot.plist␊ |
679 | ␉};␊ |
680 | ␊ |
681 | ␉int i, fd, count, ret=-1;␊ |
682 | ␊ |
683 | ␉for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++)␊ |
684 | ␉{␊ |
685 | ␉␉if ((fd = open(dirspec[i], 0)) >= 0)␊ |
686 | ␉␉{␊ |
687 | ␉␉␉// read file␊ |
688 | ␉␉␉count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);␊ |
689 | ␉␉␉close(fd);␊ |
690 | ␊ |
691 | ␉␉␉// build xml dictionary␊ |
692 | ␉␉␉ParseXMLFile(config->plist, &config->dictionary);␊ |
693 | ␉␉␉sysConfigValid = true;␉␊ |
694 | ␉␉␉ret=0;␊ |
695 | ␊ |
696 | ␉␉␉break;␊ |
697 | ␉␉}␊ |
698 | ␉}␊ |
699 | ␊ |
700 | ␉if(ret == -1) ret = loadHelperConfig(config);␊ |
701 | ␊ |
702 | ␉// Always enable canOverride flag (for SystemConfig)␊ |
703 | ␉config->canOverride = true;␊ |
704 | ␊ |
705 | ␉return ret;␊ |
706 | }␊ |
707 | ␊ |
708 | /* loadChameleonConfig␊ |
709 | *␊ |
710 | * Returns 0 - successful.␊ |
711 | *␉␉ -1 - unsuccesful.␊ |
712 | */␊ |
713 | int loadChameleonConfig(config_file_t *config, BVRef chain)␊ |
714 | {␊ |
715 | ␉char *dirspec[] = {␊ |
716 | ␉␉"/Extra/org.chameleon.Boot.plist",␊ |
717 | ␉␉"/Extra/com.apple.Boot.plist", /* DEPRECIATED */␊ |
718 | ␉};␊ |
719 | ␊ |
720 | ␉int i;␊ |
721 | ␊ |
722 | ␉for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++)␊ |
723 | ␉{␊ |
724 | ␉␉if ( loadChameleonConfigForDevice(config, "rd(0,0)", dirspec[i]) == 0 )␊ |
725 | ␉␉{␊ |
726 | ␉␉␉return 0;␊ |
727 | ␉␉}␊ |
728 | ␊ |
729 | ␉␉if ( loadChameleonConfigForDevice(config, "", dirspec[i]) == 0 )␊ |
730 | ␉␉{␊ |
731 | ␉␉␉return 0;␊ |
732 | ␉␉}␊ |
733 | ␊ |
734 | ␉␉if ( loadChameleonConfigForDevice(config, "bt(0,0)", dirspec[i]) == 0 )␊ |
735 | ␉␉{␊ |
736 | ␉␉␉return 0;␊ |
737 | ␉␉}␊ |
738 | ␉␉BVRef bvr;␊ |
739 | ␉␉for ( bvr = chain; bvr; bvr = bvr->next ) /* C99 Error */␊ |
740 | ␉␉{␊ |
741 | ␉␉␉char device[256];␊ |
742 | ␉␉␉getDeviceDescription(bvr, device);␊ |
743 | ␊ |
744 | ␉␉␉if ( loadChameleonConfigForDevice(config, device, dirspec[i]) == 0 )␊ |
745 | ␉␉␉{␊ |
746 | ␉␉␉␉return 0;␊ |
747 | ␉␉␉}␊ |
748 | ␉␉}␊ |
749 | ␉}␊ |
750 | ␉return -1;␊ |
751 | }␊ |
752 | ␊ |
753 | /* loadChameleonConfigForDevice␊ |
754 | *␊ |
755 | * Returns 0 - successful.␊ |
756 | *␉␉ -1 - unsuccesful.␊ |
757 | */␊ |
758 | int loadChameleonConfigForDevice(config_file_t *config, const char *device, const char *path)␊ |
759 | {␊ |
760 | ␉char full_path[1024];␊ |
761 | ␉int fd;␊ |
762 | ␊ |
763 | ␉snprintf(full_path, sizeof(full_path), "%s%s", device, path);␊ |
764 | ␊ |
765 | ␉if ((fd = open(full_path, 0)) >= 0)␊ |
766 | ␉{␊ |
767 | ␉␉// Check for depreciated file names and annoy the user about it.␊ |
768 | ␉␉if(strstr(full_path, "com.apple.Boot.plist")) {␊ |
769 | ␉␉␉printf("%s is depreciated.\n", full_path);␊ |
770 | ␉␉␉full_path[strlen(full_path) - strlen("com.apple.Boot.plist")] = 0;␊ |
771 | ␉␉␉printf("Please use the file %sorg.chameleon.Boot.plist instead.\n", full_path);␊ |
772 | ␉␉␉pause();␊ |
773 | ␉␉}␊ |
774 | ␉␉// read file␊ |
775 | ␉␉read(fd, config->plist, IO_CONFIG_DATA_SIZE);␊ |
776 | ␉␉close(fd);␊ |
777 | ␊ |
778 | ␉␉// build xml dictionary␊ |
779 | ␉␉ParseXMLFile(config->plist, &config->dictionary);␊ |
780 | ␉␉sysConfigValid = true;␊ |
781 | ␉␉return 0;␊ |
782 | ␉}␊ |
783 | ␉return -1;␊ |
784 | }␊ |
785 | ␊ |
786 | /* loadHelperConfig␊ |
787 | *␊ |
788 | * Returns 0 - successful.␊ |
789 | *␉␉ -1 - unsuccesful.␊ |
790 | */␊ |
791 | int loadHelperConfig(config_file_t *config)␊ |
792 | {␊ |
793 | ␉int rfd, pfd, sfd, count, ret=-1, fixedsize;␊ |
794 | ␊ |
795 | ␉char *dirspec[] = {␊ |
796 | ␉␉"/com.apple.boot.P/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",␊ |
797 | ␉␉"/com.apple.boot.R/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",␊ |
798 | ␉␉"/com.apple.boot.S/Library/Preferences/SystemConfiguration/com.apple.Boot.plist"␊ |
799 | ␉};␊ |
800 | ␊ |
801 | ␉// This is a simple rock - paper scissors algo. R beats S, P beats R, S beats P␊ |
802 | ␉// If all three, S is used for now. This should be changed to something else (say, timestamp?)␊ |
803 | ␊ |
804 | ␉pfd = open(dirspec[0], 0);␊ |
805 | ␉if(pfd >= 0)␉// com.apple.boot.P exists␊ |
806 | ␉{␊ |
807 | ␊ |
808 | ␉␉sfd = open(dirspec[2], 0); // com.apple.boot.S takes precidence if it also exists␊ |
809 | ␉␉if(sfd >= 0)␊ |
810 | ␉␉{␊ |
811 | ␉␉␉// Use sfd␊ |
812 | ␉␉␉fixedsize = MIN(file_size(sfd), IO_CONFIG_DATA_SIZE);␊ |
813 | ␉␉␉count = read(sfd, config->plist, fixedsize);␊ |
814 | ␉␉␉close(sfd);␊ |
815 | ␉␉␉close(pfd);␊ |
816 | ␉␉␉if (count != fixedsize) return -1;␊ |
817 | ␊ |
818 | ␉␉␉// build xml dictionary␊ |
819 | ␉␉␉ParseXMLFile(config->plist, &config->dictionary);␊ |
820 | ␉␉␉sysConfigValid = true;␊ |
821 | ␉␉␉ret=0;␊ |
822 | ␊ |
823 | ␉␉}␊ |
824 | ␉␉else␊ |
825 | ␉␉{␊ |
826 | ␉␉␉// used pfd␊ |
827 | ␉␉␉fixedsize = MIN(file_size(pfd), IO_CONFIG_DATA_SIZE);␊ |
828 | ␉␉␉count = read(pfd, config->plist, fixedsize);␊ |
829 | ␉␉␉close(pfd);␊ |
830 | ␉␉␉if (count != fixedsize) return -1;␊ |
831 | ␊ |
832 | ␉␉␉// build xml dictionary␊ |
833 | ␉␉␉ParseXMLFile(config->plist, &config->dictionary);␊ |
834 | ␉␉␉sysConfigValid = true;␊ |
835 | ␉␉␉ret = 0;␊ |
836 | ␉␉}␊ |
837 | ␊ |
838 | ␉}␊ |
839 | ␉else␊ |
840 | ␉{␊ |
841 | ␉␉rfd = open(dirspec[1], 0); // com.apple.boot.R exists␊ |
842 | ␉␉if(rfd >= 0)␊ |
843 | ␉␉{␊ |
844 | ␉␉␉pfd = open(dirspec[2], 0); // com.apple.boot.P takes recidence if it exists␊ |
845 | ␉␉␉if(pfd >= 0)␊ |
846 | ␉␉␉{␊ |
847 | ␉␉␉␉// use sfd␊ |
848 | ␉␉␉␉fixedsize = MIN(file_size(pfd), IO_CONFIG_DATA_SIZE);␊ |
849 | ␉␉␉␉count = read(pfd, config->plist, fixedsize);␊ |
850 | ␉␉␉␉close(pfd);␊ |
851 | ␉␉␉␉close(rfd);␊ |
852 | ␉␉␉␉if (count != fixedsize) return -1;␊ |
853 | ␊ |
854 | ␉␉␉␉// build xml dictionary␊ |
855 | ␉␉␉␉ParseXMLFile(config->plist, &config->dictionary);␊ |
856 | ␉␉␉␉sysConfigValid = true;␊ |
857 | ␉␉␉␉ret = 0;␊ |
858 | ␊ |
859 | ␉␉␉}␊ |
860 | ␉␉␉else␊ |
861 | ␉␉␉{␊ |
862 | ␉␉␉␉// use rfd␊ |
863 | ␉␉fixedsize = MIN(file_size(rfd), IO_CONFIG_DATA_SIZE);␊ |
864 | ␉␉␉␉count = read(rfd, config->plist, fixedsize);␊ |
865 | ␉␉␉␉close(rfd);␊ |
866 | ␉␉␉␉if (count != fixedsize) return -1;␊ |
867 | ␉␉␉␉␊ |
868 | ␉␉␉␉// build xml dictionary␊ |
869 | ␉␉␉␉ParseXMLFile(config->plist, &config->dictionary);␊ |
870 | ␉␉␉␉sysConfigValid = true;␊ |
871 | ␉␉␉␉ret = 0;␊ |
872 | ␊ |
873 | ␉␉␉}␊ |
874 | ␊ |
875 | ␉␉}␊ |
876 | ␉␉else␊ |
877 | ␉␉{␊ |
878 | ␉␉␉sfd = open(dirspec[2], 0); // com.apple.boot.S exists, but nothing else does␊ |
879 | ␉␉␉if(sfd >= 0)␊ |
880 | ␉␉␉{␊ |
881 | ␉␉␉␉// use sfd␊ |
882 | ␉␉␉␉fixedsize = MIN(file_size(sfd), IO_CONFIG_DATA_SIZE);␊ |
883 | ␉␉␉␉count = read(sfd, config->plist, fixedsize);␊ |
884 | ␉␉␉␉close(sfd);␊ |
885 | ␉␉␉␉if (count != fixedsize) return -1;␊ |
886 | ␊ |
887 | ␉␉␉␉// build xml dictionary␊ |
888 | ␉␉␉␉ParseXMLFile(config->plist, &config->dictionary);␊ |
889 | ␉␉␉␉sysConfigValid = true;␊ |
890 | ␉␉␉␉ret = 0;␊ |
891 | ␊ |
892 | ␉␉␉}␊ |
893 | ␉␉}␊ |
894 | ␊ |
895 | ␉}␊ |
896 | ␊ |
897 | ␉return ret;␊ |
898 | }␊ |
899 | ␊ |
900 | char * newString(const char * oldString)␊ |
901 | {␊ |
902 | ␉if ( oldString )␊ |
903 | ␉{␊ |
904 | ␉␉return strcpy(malloc(strlen(oldString)+1), oldString);␊ |
905 | ␉}␊ |
906 | ␉else␊ |
907 | ␉{␊ |
908 | ␉␉return NULL;␊ |
909 | ␉}␊ |
910 | }␊ |
911 | ␊ |
912 | /*␊ |
913 | * Extracts the next argument from the command line, double quotes are allowed here.␊ |
914 | */␊ |
915 | char * getNextArg(char ** argPtr, char * val)␊ |
916 | {␊ |
917 | ␉char * ptr = *argPtr;␊ |
918 | ␉const char * strStart;␊ |
919 | ␉int len = 0;␊ |
920 | ␉bool isQuoted = false;␊ |
921 | ␊ |
922 | ␉*val = '\0';␊ |
923 | ␊ |
924 | ␉// Scan for the next non-whitespace character.␊ |
925 | ␉while ( *ptr && (*ptr == ' ' || *ptr == '=') )␊ |
926 | ␉{␊ |
927 | ␉␉ptr++;␊ |
928 | ␉}␊ |
929 | ␊ |
930 | ␉strStart = ptr;␊ |
931 | ␊ |
932 | ␉// Skip the leading double quote character.␊ |
933 | ␉if (*ptr == '\"')␊ |
934 | ␉{␊ |
935 | ␉␉isQuoted = true;␊ |
936 | ␉␉ptr++;␊ |
937 | ␉␉strStart++;␊ |
938 | ␉}␊ |
939 | ␊ |
940 | ␉// Scan for the argument terminator character.␊ |
941 | ␉// This can be either a NULL character - in case we reach the end of the string,␊ |
942 | ␉// a double quote in case of quoted argument,␊ |
943 | ␉// or a whitespace character (' ' or '=') for non-quoted argument.␊ |
944 | ␉while (*ptr && !( (isQuoted && (*ptr == '\"')) ||␊ |
945 | (!isQuoted && (*ptr == ' ' || *ptr == '=')) )␊ |
946 | ) {␊ |
947 | ␉␉ptr++;␊ |
948 | ␉}␊ |
949 | ␊ |
950 | ␉len = ptr - strStart;␊ |
951 | ␊ |
952 | ␉// Skip the closing double quote character and adjust␊ |
953 | ␉// the starting pointer for the next getNextArg call.␊ |
954 | ␉if (*ptr && isQuoted && *ptr == '\"') {␊ |
955 | ␉␉ptr++;␊ |
956 | ␉}␊ |
957 | ␊ |
958 | ␉// Copy the extracted argument to val.␊ |
959 | ␉strncat(val, strStart, len);␊ |
960 | ␊ |
961 | ␉// Set command line pointer.␊ |
962 | ␉*argPtr = ptr;␊ |
963 | ␊ |
964 | ␉return ptr;␊ |
965 | }␊ |
966 | |