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