]>
Commit | Line | Data |
---|---|---|
14c7c974 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Portions Copyright (c) 1999 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 1.1 (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 | #import "libsaio.h" | |
30 | #import "kernBootStruct.h" | |
31 | #import "stringConstants.h" | |
32 | #import <driverkit/configTablePrivate.h> | |
33 | ||
34 | extern KERNBOOTSTRUCT *kernBootStruct; | |
35 | extern char *Language; | |
36 | extern char *LoadableFamilies; | |
37 | ||
38 | ||
39 | static char_ret | |
40 | getachar( | |
41 | char **string_p | |
42 | ) | |
43 | { | |
44 | register char *str = *string_p; | |
45 | register int c; | |
46 | char_ret r; | |
47 | ||
48 | c = *str++; | |
49 | if (c == '\\') { | |
50 | r.quoted = YES; | |
51 | c = *str++; | |
52 | switch(c) { | |
53 | case 'n': | |
54 | c = '\n'; | |
55 | break; | |
56 | case 'r': | |
57 | c = '\r'; | |
58 | break; | |
59 | case 't': | |
60 | c = '\t'; | |
61 | break; | |
62 | default: | |
63 | break; | |
64 | } | |
65 | } else { | |
66 | r.quoted = NO; | |
67 | } | |
68 | *string_p = str; | |
69 | r.c = c; | |
70 | return r; | |
71 | } | |
72 | ||
73 | /* | |
74 | * A token is: | |
75 | * <non_space_non_semicolon>* | |
76 | * "<non_quote>*" | |
77 | * <semicolon> | |
78 | */ | |
79 | char * | |
80 | get_token( | |
81 | char **string_p | |
82 | ) | |
83 | { | |
84 | char *begin; | |
85 | char *newstr; | |
86 | char_ret r; | |
87 | int len; | |
88 | ||
89 | do { | |
90 | r = getachar(string_p); | |
91 | } while (r.c && isspace(r.c)); | |
92 | ||
93 | if (!r.quoted && r.c == '\"') { | |
94 | begin = *string_p; | |
95 | do { | |
96 | r = getachar(string_p); | |
97 | } while (r.c && !r.quoted && r.c != '\"'); | |
98 | } else { | |
99 | begin = *string_p - 1; | |
100 | do { | |
101 | r = getachar(string_p); | |
102 | } while (r.c && !r.quoted && r.c != ';' && !isspace(r.c)); | |
103 | } | |
104 | len = *string_p - begin - 1; | |
105 | newstr = (char *)malloc(len + 1); | |
106 | strncpy(newstr, begin, len); | |
107 | newstr[len] = '\0'; | |
108 | return newstr; | |
109 | } | |
110 | ||
111 | ||
112 | char * | |
113 | stringFromList( | |
114 | char **list, | |
115 | int *size | |
116 | ) | |
117 | { | |
118 | char *begin = *list, *end; | |
119 | char *newstr; | |
120 | int newsize = *size; | |
121 | ||
122 | while (*begin && newsize && isspace(*begin)) { | |
123 | begin++; | |
124 | newsize--; | |
125 | } | |
126 | end = begin; | |
127 | while (*end && newsize && !isspace(*end)) { | |
128 | end++; | |
129 | newsize--; | |
130 | } | |
131 | if (begin == end) | |
132 | return 0; | |
133 | newstr = malloc(end - begin + 1); | |
134 | strncpy(newstr, begin, end - begin); | |
135 | *list = end; | |
136 | *size = newsize; | |
137 | return newstr; | |
138 | } | |
139 | ||
140 | char * | |
141 | valueForStringTableKey( | |
142 | char *table, | |
143 | char *key | |
144 | ) | |
145 | { | |
146 | char *token; | |
147 | enum { | |
148 | KEY, | |
149 | EQUALS, | |
150 | VALUE, | |
151 | SEMICOLON, | |
152 | BEGINCOMMENT, | |
153 | ENDCOMMENT | |
154 | } state; | |
155 | BOOL foundKey; | |
156 | int len; | |
157 | ||
158 | state = KEY; | |
159 | foundKey = NO; | |
160 | while (*table) { | |
161 | token = get_token(&table); | |
162 | switch(state) { | |
163 | case KEY: | |
164 | if (strcmp(token, key) == 0) | |
165 | foundKey = YES; | |
166 | if (strncmp(token, "/*", 2) == 0) | |
167 | state = ENDCOMMENT; | |
168 | else | |
169 | state = EQUALS; | |
170 | break; | |
171 | case EQUALS: | |
172 | if (strcmp(token, "=") == 0) { | |
173 | state = VALUE; | |
174 | } | |
175 | break; | |
176 | case VALUE: | |
177 | if (foundKey) { | |
178 | return token; | |
179 | } | |
180 | state = SEMICOLON; | |
181 | break; | |
182 | case SEMICOLON: | |
183 | if (strcmp(token, ";") == 0) { | |
184 | state = KEY; | |
185 | } | |
186 | break; | |
187 | case ENDCOMMENT: | |
188 | len = strlen(token); | |
189 | if (len >= 2 && strncmp(token + len - 2, "*/", 2) == 0) | |
190 | state = KEY; | |
191 | break; | |
192 | } | |
193 | free(token); | |
194 | } | |
195 | return 0; | |
196 | } | |
197 | ||
198 | char * | |
199 | valueForBootKey( | |
200 | char *line, | |
201 | char *match | |
202 | ) | |
203 | { | |
204 | char *token; | |
205 | enum { | |
206 | KEY, | |
207 | EQUALS, | |
208 | VALUE, | |
209 | WHITESPACE | |
210 | } state; | |
211 | BOOL foundKey; | |
212 | int len; | |
213 | ||
214 | state = KEY; | |
215 | while (*line) { | |
216 | token = get_token(&line); | |
217 | } | |
218 | } | |
219 | ||
220 | BOOL | |
221 | boolForKey( | |
222 | char *key | |
223 | ) | |
224 | { | |
225 | char *str = valueForKey(key); | |
226 | BOOL ret; | |
227 | ||
228 | if (str && (str[0] == 'Y' || str[1] == 'y')) | |
229 | ret = YES; | |
230 | else | |
231 | ret = NO; | |
232 | free(str); | |
233 | return ret; | |
234 | } | |
235 | ||
236 | BOOL | |
237 | getIntForKey( | |
238 | char *key, | |
239 | int *value | |
240 | ) | |
241 | { | |
242 | char *str = valueForKey(key), *ptr = str; | |
243 | int sum; | |
244 | BOOL ret; | |
245 | ||
246 | if (str) { | |
247 | for (sum = 0; size > 0; size--) { | |
248 | sum = (sum * 10) + (*ptr++ - '0'); | |
249 | } | |
250 | *value = sum; | |
251 | ret = YES; | |
252 | } else { | |
253 | ret = NO; | |
254 | } | |
255 | free(str); | |
256 | return ret; | |
257 | } | |
258 | ||
259 | char * | |
260 | valueForKey( | |
261 | char *key | |
262 | ) | |
263 | { | |
264 | char *str = valueForBootKey(kernBootStruct->bootString, key);; | |
265 | ||
266 | if (str) | |
267 | return str; | |
268 | else | |
269 | return valueForStringTableKey(kernBootStruct->config, key); | |
270 | } | |
271 | ||
272 | #define LOCALIZABLE_PATH \ | |
273 | "%s/%s.config/%s.lproj/%s.strings" | |
274 | char * | |
275 | loadLocalizableStrings( | |
276 | char *name, | |
277 | char *tableName | |
278 | ) | |
279 | { | |
280 | char buf[256], *config; | |
281 | register int i, count, fd = -1; | |
282 | char * paths[] = { | |
283 | ARCH_DEVICES, | |
284 | USR_DEVICES, | |
285 | "/", | |
286 | NULL | |
287 | }, **path; | |
288 | ||
289 | for (i=0; i<2; i++) { | |
290 | for (path = paths; *path; path++) { | |
291 | sprintf(buf, LOCALIZABLE_PATH, *path, name, | |
292 | (i == 0) ? Language : "English", tableName); | |
293 | if ((fd = open(buf, 0)) >= 0) { | |
294 | i = 2; | |
295 | break; | |
296 | } | |
297 | } | |
298 | } | |
299 | if (fd < 0) | |
300 | return 0; | |
301 | count = file_size(fd); | |
302 | config = malloc(count); | |
303 | count = read(fd, config, count); | |
304 | close(fd); | |
305 | if (count <= 0) { | |
306 | free(config); | |
307 | return 0; | |
308 | } | |
309 | return config; | |
310 | } | |
311 | ||
312 | char * | |
313 | bundleLongName( | |
314 | char *bundleName, | |
315 | char *tableName | |
316 | ) | |
317 | { | |
318 | char *table, *name, *val; | |
319 | int size; | |
320 | ||
321 | table = loadLocalizableStrings(bundleName, | |
322 | tableName ? tableName : "Localizable"); | |
323 | if ( table != 0 && | |
324 | getValueForStringTableKey(table,"Long Name", &val, &size) == YES) { | |
325 | name = malloc(size+1); | |
326 | strncpy(name, val, size); | |
327 | free(table); | |
328 | } else { | |
329 | name = newString(bundleName); | |
330 | } | |
331 | return name; | |
332 | } | |
333 | ||
334 | int sysConfigValid; | |
335 | ||
336 | void | |
337 | addConfig( | |
338 | char *config | |
339 | ) | |
340 | { | |
341 | char *configPtr = kernBootStruct->configEnd; | |
342 | int len = strlen(config); | |
343 | ||
344 | if ((configPtr - kernBootStruct->config) > CONFIG_SIZE) { | |
345 | error("No room in memory for config files\n"); | |
346 | return; | |
347 | } | |
348 | strcpy(configPtr, config); | |
349 | configPtr += (len + 1); | |
350 | *configPtr = 0; | |
351 | kernBootStruct->configEnd = configPtr; | |
352 | } | |
353 | ||
354 | /* | |
355 | * Returns 0 if file loaded OK, | |
356 | * -1 if file was not loaded | |
357 | * Does not print error messages. | |
358 | * Returns pointer to table in memory in *table. | |
359 | */ | |
360 | int | |
361 | loadConfigFile( char *configFile, char **table, BOOL allocTable) | |
362 | { | |
363 | char *configPtr = kernBootStruct->configEnd; | |
364 | int fd, count; | |
365 | ||
366 | /* Read config file into memory */ | |
367 | if ((fd = open(configFile, 0)) >= 0) | |
368 | { | |
369 | if (allocTable) { | |
370 | configPtr = malloc(file_size(fd)+2); | |
371 | } else { | |
372 | if ((configPtr - kernBootStruct->config) > CONFIG_SIZE) { | |
373 | error("No room in memory for config files\n"); | |
374 | close(fd); | |
375 | return -1; | |
376 | } | |
377 | verbose("Reading configuration file '%s'.\n",configFile); | |
378 | } | |
379 | if (table) *table = configPtr; | |
380 | count = read(fd, configPtr, IO_CONFIG_DATA_SIZE); | |
381 | close(fd); | |
382 | ||
383 | configPtr += count; | |
384 | *configPtr++ = 0; | |
385 | *configPtr = 0; | |
386 | if (!allocTable) | |
387 | kernBootStruct->configEnd = configPtr; | |
388 | ||
389 | return 0; | |
390 | } else { | |
391 | return -1; | |
392 | } | |
393 | } | |
394 | ||
395 | /* Returns 0 if requested config files were loaded, | |
396 | * 1 if default files were loaded, | |
397 | * -1 if no files were loaded. | |
398 | * Prints error message if files cannot be loaded. | |
399 | */ | |
400 | ||
401 | int | |
402 | loadConfigDir( | |
403 | char *bundleName, // bundle directory name (e.g. "System") | |
404 | BOOL useDefault, // use Default.table instead of instance tables | |
405 | char **table, // returns pointer to config table | |
406 | BOOL allocTable // malloc the table and return in *table | |
407 | ) | |
408 | { | |
409 | char *buf; | |
410 | int i, ret; | |
411 | BOOL archConfig = dirExists(ARCH_DEVICES); | |
412 | ||
413 | buf = malloc(256); | |
414 | ret = 0; | |
415 | ||
416 | // load up to 99 instance tables | |
417 | for (i=0; i < 99; i++) { | |
418 | sprintf(buf, "%s/%s.config/Instance%d.table", | |
419 | archConfig ? ARCH_DEVICES : USR_DEVICES, | |
420 | bundleName, i); | |
421 | if (useDefault || (loadConfigFile(buf, table, allocTable) != 0)) { | |
422 | if (i == 0) { | |
423 | // couldn't load first instance table; | |
424 | // try the default table | |
425 | sprintf(buf, "%s/%s.config/%s", | |
426 | archConfig ? ARCH_DEVICES : USR_DEVICES, | |
427 | bundleName, | |
428 | IO_DEFAULT_TABLE_FILENAME); | |
429 | if (loadConfigFile(buf, table, allocTable) == 0) { | |
430 | ret = 1; | |
431 | } else { | |
432 | if (!allocTable) | |
433 | error("Config file \"%s\" not found\n", buf); | |
434 | ret = -1; | |
435 | } | |
436 | } | |
437 | // we must be done. | |
438 | break; | |
439 | } | |
440 | } | |
441 | free(buf); | |
442 | return ret; | |
443 | } | |
444 | ||
445 | ||
446 | #define USR_SYSTEM_CONFIG \ | |
447 | USR_DEVICES "/System.config" | |
448 | #define USR_SYSTEM_DEFAULT_FILE \ | |
449 | USR_SYSTEM_CONFIG "/Default.table" | |
450 | #define ARCH_SYSTEM_CONFIG \ | |
451 | ARCH_DEVICES "/System.config" | |
452 | #define ARCH_SYSTEM_DEFAULT_FILE \ | |
453 | ARCH_SYSTEM_CONFIG "/Default.table" | |
454 | #define SYSTEM_CONFIG "System" | |
455 | #define LP '(' | |
456 | #define RP ')' | |
457 | ||
458 | /* Returns 0 if requested config files were loaded, | |
459 | * 1 if default files were loaded, | |
460 | * -1 if no files were loaded. | |
461 | * Prints error message if files cannot be loaded. | |
462 | */ | |
463 | int | |
464 | loadSystemConfig( | |
465 | char *which, | |
466 | int size | |
467 | ) | |
468 | { | |
469 | char *buf, *bp, *cp; | |
470 | int ret, len, doDefault=0; | |
471 | BOOL archConfig = dirExists(ARCH_DEVICES); | |
472 | ||
473 | buf = bp = malloc(256); | |
474 | if (which && size) | |
475 | { | |
476 | for(cp = which, len = size; len && *cp && *cp != LP; cp++, len--) ; | |
477 | if (*cp == LP) { | |
478 | while (len-- && *cp && *cp++ != RP) ; | |
479 | /* cp now points past device */ | |
480 | strncpy(buf,which,cp - which); | |
481 | bp += cp - which; | |
482 | } else { | |
483 | cp = which; | |
484 | len = size; | |
485 | } | |
486 | if (*cp != '/') { | |
487 | strcpy(bp, archConfig ? | |
488 | ARCH_SYSTEM_CONFIG : USR_SYSTEM_CONFIG); | |
489 | strcat(bp, "/"); | |
490 | strncat(bp, cp, len); | |
491 | if (strncmp(cp + len - strlen(IO_TABLE_EXTENSION), | |
492 | IO_TABLE_EXTENSION, strlen(IO_TABLE_EXTENSION)) != 0) | |
493 | strcat(bp, IO_TABLE_EXTENSION); | |
494 | } else { | |
495 | strncpy(bp, cp, len); | |
496 | bp[size] = '\0'; | |
497 | } | |
498 | if ((strcmp(bp, USR_SYSTEM_DEFAULT_FILE) == 0) || | |
499 | (strcmp(bp, ARCH_SYSTEM_DEFAULT_FILE) == 0)) | |
500 | doDefault = 1; | |
501 | ret = loadConfigFile(bp = buf, 0, 0); | |
502 | } else { | |
503 | ret = loadConfigDir((bp = SYSTEM_CONFIG), 0, 0, 0); | |
504 | } | |
505 | if (ret < 0) { | |
506 | error("System config file '%s' not found\n", bp); | |
507 | } else | |
508 | sysConfigValid = 1; | |
509 | free(buf); | |
510 | return (ret < 0 ? ret : doDefault); | |
511 | } | |
512 | ||
513 | ||
514 | int | |
515 | loadOtherConfigs( | |
516 | int useDefault | |
517 | ) | |
518 | { | |
519 | char *val, *table; | |
520 | int count; | |
521 | char *string; | |
522 | int fd, ret; | |
523 | ||
524 | if (getValueForKey( "Boot Drivers", &val, &count)) | |
525 | { | |
526 | while (string = stringFromList(&val, &count)) { | |
527 | ret = loadConfigDir(string, useDefault, &table, 0); | |
528 | if (ret >= 0) { | |
529 | if ((fd = openDriverReloc(string)) >= 0) { | |
530 | verbose("Loading binary for %s device driver.\n",string); | |
531 | if (loadDriver(string, fd) < 0) | |
532 | error("Error loading %s device driver.\n",string); | |
533 | close(fd); | |
534 | } | |
535 | driverWasLoaded(string, table, NULL); | |
536 | free(string); | |
537 | } else { | |
538 | driverIsMissing(string); | |
539 | } | |
540 | } | |
541 | } else { | |
542 | error("Warning: No active drivers specified in system config.\n"); | |
543 | } | |
544 | ||
545 | kernBootStruct->first_addr0 = | |
546 | (int)kernBootStruct->configEnd + 1024; | |
547 | return 0; | |
548 | } | |
549 | ||
550 | static BOOL | |
551 | dirExists(char *path) | |
552 | { | |
553 | int fd; | |
554 | ||
555 | if ((fd = open(path, 0)) < 0) { | |
556 | return NO; | |
557 | } else { | |
558 | close(fd); | |
559 | return YES; | |
560 | } | |
561 | } | |
562 | ||
563 | ||
564 |