/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 1.1 (the "License"). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Copyright 1993 NeXT, Inc. * All rights reserved. */ //#import "libsaio.h" //#import "bootstruct.h" //#import <driverkit/configTablePrivate.h> extern char *Language; extern char *LoadableFamilies; static void eatThru(char val, char **table_p); static __inline INTN isspace(char c) { return (c == ' ' || c == '\t'); } /* * Compare a string to a key with quoted characters */ static __inline int keyncmp(char *str, char *key, INTN n) { INTN c; while (n--) { c = *key++; if (c == '\\') { switch(c = *key++) { case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; default: break; } } else if (c == '\"') { /* Premature end of key */ return 1; } if (c != *str++) { return 1; } } return 0; } static void eatThru(char val, char **table_p) { register char *table = *table_p; register BOOL found = NO; while (*table && !found) { if (*table == '\\') table += 2; else { if (*table == val) found = YES; table++; } } *table_p = table; } char * newStringFromList( char **list, INTN* size ) { char *begin = *list, *end; char *newstr; INTN newsize = *size; while (*begin && newsize && isspace(*begin)) { begin++; newsize--; } end = begin; while (*end && newsize && !isspace(*end)) { end++; newsize--; } if (begin == end) return 0; newstr = malloc(end - begin + 1); strncpy(newstr, begin, end - begin); *list = end; *size = newsize; return newstr; } /* * compress == compress escaped characters to one character */ int stringLength(char *table, INTN compress) { int ret = 0; while (*table) { if (*table == '\\') { table += 2; ret += 1 + (compress ? 0 : 1); } else { if (*table == '\"') return ret; ret++; table++; } } return ret; } // looks in table for strings of format << "key" = "value"; >> // or << "key"; >> BOOL getValueForStringTableKey(char *table, char *key, char **val, INTN *size) { INTN keyLength; char *tableKey; do { eatThru('\"',&table); tableKey = table; keyLength = strlen(key); if (keyLength && (stringLength(table,1) == keyLength) && (keyncmp(key, table, keyLength) == 0)) { INTN c; /* found the key; now look for either * '=' or ';' */ while (c = *table) { ++table; if (c == '\\') { ++table; continue; } else if (c == '=' || c == ';') { break; } } if (c == ';') { table = tableKey; } else { eatThru('\"',&table); } *val = table; *size = stringLength(table,0); return YES; } eatThru(';',&table); } while (*table); return NO; } /* * Returns a new malloc'ed string if one is found * in the string table matching 'key'. Also translates * \n escapes in the string. */ char *newStringForStringTableKey( char *table, char *key ) { char *val, *newstr, *p; INTN size; if (getValueForStringTableKey(table, key, &val, &size)) { newstr = malloc(size+1); for (p = newstr; size; size--, p++, val++) { if ((*p = *val) == '\\') { switch (*++val) { case 'r': *p = '\r'; break; case 'n': *p = '\n'; break; case 't': *p = '\t'; break; default: *p = *val; break; } size--; } } *p = '\0'; return newstr; } else { return 0; } } char * newStringForKey(char *key) { char *val, *newstr; INTN size; if (getValueForKey(key, &val, &size) && size) { newstr = malloc(size + 1); strncpy(newstr, val, size); return newstr; } else { return 0; } } /* parse a command line * in the form: [<argument> ...] [<option>=<value> ...] * both <option> and <value> must be either composed of * non-whitespace characters, or enclosed in quotes. */ static char *getToken(char *line, char **begin, INTN *len) { if (*line == '\"') { *begin = ++line; while (*line && *line != '\"') line++; *len = line++ - *begin; } else { *begin = line; while (*line && !isspace(*line) && *line != '=') line++; *len = line - *begin; } return line; } BOOL getValueForBootKey(char *line, char *match, char **matchval, INTN *len) { char *key, *value; INTN key_len, value_len; while (*line) { /* look for keyword or argument */ while (isspace(*line)) line++; /* now look for '=' or whitespace */ line = getToken(line, &key, &key_len); /* line now points to '=' or space */ if (!isspace(*line++)) { line = getToken(line, &value, &value_len); if ((strlen(match) == key_len) && strncmp(match, key, key_len) == 0) { *matchval = value; *len = value_len; return YES; } } } return NO; } BOOL getBoolForKey( char *key ) { char *val; INTN, size; if (getValueForKey(key, &val, &size) && (size >= 1) && val[0] == 'Y' || val[0] == 'y') return YES; return NO; } BOOL getValueForKey( char *key, char **val, INTN *size ) { if (getValueForBootKey(bootArgs->bootString, key, val, size)) return YES; else if (getValueForStringTableKey(bootArgs->config, key, val, size)) return YES; return NO; } #define LOCALIZABLE \ "/usr/Devices/%s.config/%s.lproj/Localizable.strings" char * loadLocalizableStrings( char *name ) { char buf[256], *config; register INTN count, fd; sprintf(buf, LOCALIZABLE, name, Language); if ((fd = open(buf,0)) < 0) { sprintf(buf, LOCALIZABLE, name, "English"); if ((fd = open(buf,0)) < 0) return 0; } count = file_size(fd); config = malloc(count); count = read(fd, config, count); close(fd); if (count <= 0) { free(config); return 0; } return config; } char * bundleLongName( char *bundleName ) { char *table, *name, *val; INTN, size; if ((table = loadLocalizableStrings(bundleName)) != 0 && getValueForStringTableKey(table,"Long Name", &val, &size) == YES) { name = malloc(size+1); strncpy(name, val, size); free(table); } else { name = newString(bundleName); } return name; } int sysConfigValid; /* * Returns 0 if file loaded OK, * -1 if file was not loaded * Does not print error messages. * Returns pointer to table in memory in *table. */ int loadConfigFile( char *configFile, char **table, INTN allocTable) { char *configPtr = bootArgs->configEnd; INTN fd, count; /* Read config file into memory */ if ((fd = open(configFile, 0)) >= 0) { if (allocTable) { configPtr = malloc(file_size(fd)+2); } else { if ((configPtr - bootArgs->config) > CONFIG_SIZE) { error("No room in memory for config file %s\n",configFile); close(fd); return -1; } localPrintf("Reading config: %s\n",configFile); } if (table) *table = configPtr; count = read(fd, configPtr, IO_CONFIG_DATA_SIZE); close(fd); configPtr += count; *configPtr++ = 0; *configPtr = 0; if (!allocTable) bootArgs->configEnd = configPtr; return 0; } else { return -1; } } /* Returns 0 if requested config files were loaded, * 1 if default files were loaded, * -1 if no files were loaded. * Prints error message if files cannot be loaded. */ int loadConfigDir( char *bundleName, // bundle directory name (e.g. "System.config") INTN useDefault, // use Default.table instead of instance tables char **table, // returns pointer to config table INTN allocTable // malloc the table and return in *table ) { char *buf; INTN i, ret; buf = malloc(256); ret = 0; // load up to 99 instance tables for (i=0; i < 99; i++) { sprintf(buf, "%s%s.config/Instance%d.table", IO_CONFIG_DIR, bundleName, i); if (useDefault || (loadConfigFile(buf, table, allocTable) != 0)) { if (i == 0) { // couldn't load first instance table; // try the default table sprintf(buf, "%s%s.config/%s", IO_CONFIG_DIR, bundleName, IO_DEFAULT_TABLE_FILENAME); if (loadConfigFile(buf, table, allocTable) == 0) { ret = 1; } else { if (!allocTable) error("Config file \"%s\" not found\n", buf); ret = -1; } } // we must be done. break; } } free(buf); return ret; } #define SYSTEM_DEFAULT_FILE \ IO_SYSTEM_CONFIG_DIR IO_DEFAULT_TABLE_FILENAME #define SYSTEM_CONFIG "System" #define LP '(' #define RP ')' /* Returns 0 if requested config files were loaded, * 1 if default files were loaded, * -1 if no files were loaded. * Prints error message if files cannot be loaded. */ int loadSystemConfig( char *which, INTN size ) { char *buf, *bp, *cp; INTN ret, len, doDefault=0; buf = bp = malloc(256); if (which && size) { for(cp = which, len = size; len && *cp && *cp != LP; cp++, len--) ; if (*cp == LP) { while (len-- && *cp && *cp++ != RP) ; /* cp now points past device */ strncpy(buf,which,cp - which); bp += cp - which; } else { cp = which; len = size; } if (*cp != '/') { strcpy(bp, IO_SYSTEM_CONFIG_DIR); strncat(bp, cp, len); if (strncmp(cp + len - strlen(IO_TABLE_EXTENSION), IO_TABLE_EXTENSION, strlen(IO_TABLE_EXTENSION)) != 0) strcat(bp, IO_TABLE_EXTENSION); } else { strncpy(bp, cp, len); bp[size] = '\0'; } if (strcmp(bp, SYSTEM_DEFAULT_FILE) == 0) doDefault = 1; ret = loadConfigFile(bp = buf, 0, 0); } else { ret = loadConfigDir((bp = SYSTEM_CONFIG), 0, 0, 0); } if (ret < 0) { error("System config file '%s' not found\n", bp); } else sysConfigValid = 1; free(buf); return (ret < 0 ? ret : doDefault); } int loadOtherConfigs( INTN useDefault ) { char *val, *table; INTN count; char *string; INTN fd, ret; if (getValueForKey( "Boot Drivers", &val, &count)) { while (string = newStringFromList(&val, &count)) { ret = loadConfigDir(string, useDefault, &table, 0); if (ret >= 0) { if ((fd = openDriverReloc(string)) >= 0) { localPrintf("Loading binary for %s\n",string); if (loadDriver(string, fd) < 0) error("Error loading driver %s\n",string); close(fd); } driverWasLoaded(string, table); free(string); } else { driverIsMissing(string); } if (ret == 1) useDefault = 1; // use defaults from now on } } else { error("Warning: No active drivers specified in system config\n"); } bootArgs->first_addr0 = (int)bootArgs->configEnd + 1024; return 0; }