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