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