1 /* 2 * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <safemode.h> 8 9 #include <ctype.h> 10 #include <string.h> 11 12 #include <algorithm> 13 14 #include <KernelExport.h> 15 16 #include <boot/kernel_args.h> 17 #include <kernel.h> 18 #include <syscalls.h> 19 20 21 #ifndef _BOOT_MODE 22 23 24 static status_t 25 get_option_from_kernel_args(kernel_args* args, const char* settingsName, 26 const char* parameter, size_t parameterLength, char* buffer, 27 size_t* _bufferSize) 28 { 29 // find the settings in the kernel args 30 const char* settings = NULL; 31 for (driver_settings_file* file = args->driver_settings; 32 file != NULL; file = file->next) { 33 if (strcmp(settingsName, file->name) == 0) { 34 settings = file->buffer; 35 break; 36 } 37 } 38 39 if (settings == NULL) 40 return B_ENTRY_NOT_FOUND; 41 42 // Unfortunately we can't just use parse_driver_settings_string(), since 43 // we might not have a working heap yet. So we do very limited parsing 44 // ourselves. 45 const char* settingsEnd = settings + strlen(settings); 46 int32 parameterLevel = 0; 47 48 while (*settings != '\0') { 49 // find end of line 50 const char* lineEnd = strchr(settings, '\n'); 51 const char* nextLine; 52 if (lineEnd != NULL) 53 nextLine = lineEnd + 1; 54 else 55 nextLine = lineEnd = settingsEnd; 56 57 // ignore any trailing comments 58 lineEnd = std::find(settings, lineEnd, '#'); 59 60 const char* nameStart = NULL; 61 const char* nameEnd = NULL; 62 const char* valueStart = NULL; 63 const char* valueEnd = NULL; 64 const char** elementEnd = NULL; 65 bool sawSeparator = true; 66 67 for (; settings < lineEnd; settings++) { 68 switch (*settings) { 69 case '{': 70 parameterLevel++; 71 sawSeparator = true; 72 break; 73 74 case '}': 75 parameterLevel--; 76 sawSeparator = true; 77 break; 78 79 case ';': 80 // TODO: That's not correct. There should be another loop. 81 sawSeparator = true; 82 break; 83 84 default: 85 if (parameterLevel != 0) 86 break; 87 88 if (isspace(*settings)) { 89 sawSeparator = true; 90 break; 91 } 92 93 if (!sawSeparator) 94 break; 95 96 sawSeparator = false; 97 98 if (nameStart == NULL) { 99 nameStart = settings; 100 elementEnd = &nameEnd; 101 } else if (valueStart == NULL) { 102 valueStart = settings; 103 elementEnd = &valueEnd; 104 } 105 break; 106 } 107 108 if (sawSeparator && elementEnd != NULL) { 109 *elementEnd = settings; 110 elementEnd = NULL; 111 } 112 } 113 114 if (elementEnd != NULL) 115 *elementEnd = settings; 116 117 if (nameStart != NULL && size_t(nameEnd - nameStart) == parameterLength 118 && strncmp(parameter, nameStart, parameterLength) == 0) { 119 if (valueStart == NULL) 120 return B_NAME_NOT_FOUND; 121 122 size_t length = valueEnd - valueStart; 123 if (*_bufferSize > 0) { 124 size_t toCopy = std::min(length, *_bufferSize - 1); 125 memcpy(buffer, valueStart, toCopy); 126 buffer[toCopy] = '\0'; 127 } 128 129 *_bufferSize = length; 130 return B_OK; 131 } 132 133 settings = nextLine; 134 } 135 136 return B_NAME_NOT_FOUND; 137 } 138 139 140 #endif // !_BOOT_MODE 141 142 143 static status_t 144 get_option(kernel_args* args, const char* settingsName, const char* parameter, 145 size_t parameterLength, char* buffer, size_t* _bufferSize) 146 { 147 #ifndef _BOOT_MODE 148 if (args != NULL) { 149 return get_option_from_kernel_args(args, settingsName, parameter, 150 parameterLength, buffer, _bufferSize); 151 } 152 #endif 153 154 void* handle = load_driver_settings(settingsName); 155 if (handle == NULL) 156 return B_ENTRY_NOT_FOUND; 157 158 status_t status = B_NAME_NOT_FOUND; 159 160 const char* value = get_driver_parameter(handle, parameter, NULL, NULL); 161 if (value != NULL) { 162 *_bufferSize = strlcpy(buffer, value, *_bufferSize); 163 status = B_OK; 164 } 165 166 unload_driver_settings(handle); 167 return status; 168 } 169 170 171 static status_t 172 get_option(kernel_args* args, const char* parameter, char* buffer, 173 size_t* _bufferSize) 174 { 175 size_t parameterLength = strlen(parameter); 176 status_t status = get_option(args, B_SAFEMODE_DRIVER_SETTINGS, parameter, 177 parameterLength, buffer, _bufferSize); 178 if (status != B_OK) { 179 // Try kernel settings file as a fall back 180 status = get_option(args, "kernel", parameter, parameterLength, buffer, 181 _bufferSize); 182 } 183 184 return status; 185 } 186 187 188 static bool 189 get_boolean(kernel_args* args, const char* parameter, bool defaultValue) 190 { 191 char value[16]; 192 size_t length = sizeof(value); 193 194 if (get_option(args, parameter, value, &length) != B_OK) 195 return defaultValue; 196 197 return !strcasecmp(value, "on") || !strcasecmp(value, "true") 198 || !strcmp(value, "1") || !strcasecmp(value, "yes") 199 || !strcasecmp(value, "enabled"); 200 } 201 202 203 // #pragma mark - 204 205 206 status_t 207 get_safemode_option(const char* parameter, char* buffer, size_t* _bufferSize) 208 { 209 return get_option(NULL, parameter, buffer, _bufferSize); 210 } 211 212 213 bool 214 get_safemode_boolean(const char* parameter, bool defaultValue) 215 { 216 return get_boolean(NULL, parameter, defaultValue); 217 } 218 219 220 #ifndef _BOOT_MODE 221 222 223 status_t 224 get_safemode_option_early(kernel_args* args, const char* parameter, 225 char* buffer, size_t* _bufferSize) 226 { 227 return get_option(args, parameter, buffer, _bufferSize); 228 } 229 230 231 bool 232 get_safemode_boolean_early(kernel_args* args, const char* parameter, 233 bool defaultValue) 234 { 235 return get_boolean(args, parameter, defaultValue); 236 } 237 238 239 #endif // _BOOT_MODE 240 241 242 // #pragma mark - syscalls 243 244 245 #ifndef _BOOT_MODE 246 247 248 extern "C" status_t 249 _user_get_safemode_option(const char* userParameter, char* userBuffer, 250 size_t* _userBufferSize) 251 { 252 char parameter[B_FILE_NAME_LENGTH]; 253 char buffer[B_PATH_NAME_LENGTH]; 254 size_t bufferSize, originalBufferSize; 255 256 if (!IS_USER_ADDRESS(userParameter) || !IS_USER_ADDRESS(userBuffer) 257 || !IS_USER_ADDRESS(_userBufferSize) 258 || user_memcpy(&bufferSize, _userBufferSize, sizeof(size_t)) != B_OK 259 || user_strlcpy(parameter, userParameter, B_FILE_NAME_LENGTH) < B_OK) 260 return B_BAD_ADDRESS; 261 262 if (bufferSize > B_PATH_NAME_LENGTH) 263 bufferSize = B_PATH_NAME_LENGTH; 264 265 originalBufferSize = bufferSize; 266 status_t status = get_safemode_option(parameter, buffer, &bufferSize); 267 268 if (status == B_OK 269 && (user_strlcpy(userBuffer, buffer, originalBufferSize) < B_OK 270 || user_memcpy(_userBufferSize, &bufferSize, sizeof(size_t)) 271 != B_OK)) 272 return B_BAD_ADDRESS; 273 274 return status; 275 } 276 277 278 #endif // !_BOOT_MODE 279