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