kernel safemode: Add functions to get options early

Add get_safemode_option_early() and get_safemode_boolean_early() to get
safemode options before the kernel heap has been initialized. They use a
simplified parser.
This commit is contained in:
Ingo Weinhold 2013-12-10 19:05:47 +01:00
parent 7a1e706df7
commit 9bdb5e0a92
2 changed files with 213 additions and 29 deletions

View File

@ -11,6 +11,9 @@
#include <safemode_defs.h>
struct kernel_args;
#ifdef __cplusplus
extern "C" {
#endif
@ -19,6 +22,13 @@ extern "C" {
status_t get_safemode_option(const char* parameter, char* buffer,
size_t* _bufferSize);
bool get_safemode_boolean(const char* parameter, bool defaultValue);
// before driver_settings_init() has been called (limited parsing support)
status_t get_safemode_option_early(kernel_args* args, const char* parameter,
char* buffer, size_t* _bufferSize);
bool get_safemode_boolean_early(kernel_args* args, const char* parameter,
bool defaultValue);
status_t _user_get_safemode_option(const char* parameter, char* buffer,
size_t* _bufferSize);

View File

@ -4,59 +4,194 @@
*/
#include <safemode.h>
#include <ctype.h>
#include <string.h>
#include <algorithm>
#include <KernelExport.h>
#include <safemode.h>
#include <boot/kernel_args.h>
#include <kernel.h>
#include <syscalls.h>
#include <string.h>
#ifndef _BOOT_MODE
extern "C" status_t
get_safemode_option(const char* parameter, char* buffer, size_t* _bufferSize)
static status_t
get_option_from_kernel_args(kernel_args* args, const char* settingsName,
const char* parameter, size_t parameterLength, char* buffer,
size_t* _bufferSize)
{
status_t status = B_ENTRY_NOT_FOUND;
void* handle = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS);
if (handle != NULL) {
status = B_NAME_NOT_FOUND;
const char* value = get_driver_parameter(handle, parameter, NULL, NULL);
if (value != NULL) {
*_bufferSize = strlcpy(buffer, value, *_bufferSize);
status = B_OK;
// find the settings in the kernel args
const char* settings = NULL;
for (driver_settings_file* file = args->driver_settings;
file != NULL; file = file->next) {
if (strcmp(settingsName, file->name) == 0) {
settings = file->buffer;
break;
}
unload_driver_settings(handle);
}
if (status != B_OK) {
// Try kernel settings file as a fall back
handle = load_driver_settings("kernel");
if (handle != NULL) {
const char* value = get_driver_parameter(handle, parameter, NULL,
NULL);
if (value != NULL) {
*_bufferSize = strlcpy(buffer, value, *_bufferSize);
status = B_OK;
if (settings == NULL)
return B_ENTRY_NOT_FOUND;
// Unfortunately we can't just use parse_driver_settings_string(), since
// we might not have a working heap yet. So we do very limited parsing
// ourselves.
const char* settingsEnd = settings + strlen(settings);
int32 parameterLevel = 0;
while (*settings != '\0') {
// find end of line
const char* lineEnd = strchr(settings, '\n');
const char* nextLine;
if (lineEnd != NULL)
nextLine = lineEnd + 1;
else
nextLine = lineEnd = settingsEnd;
// ignore any trailing comments
lineEnd = std::find(settings, lineEnd, '#');
const char* nameStart = NULL;
const char* nameEnd = NULL;
const char* valueStart = NULL;
const char* valueEnd = NULL;
const char** elementEnd = NULL;
bool sawSeparator = true;
for (; settings < lineEnd; settings++) {
switch (*settings) {
case '{':
parameterLevel++;
sawSeparator = true;
break;
case '}':
parameterLevel--;
sawSeparator = true;
break;
case ';':
// TODO: That's not correct. There should be another loop.
sawSeparator = true;
break;
default:
if (parameterLevel != 0)
break;
if (isspace(*settings)) {
sawSeparator = true;
break;
}
if (!sawSeparator)
break;
sawSeparator = false;
if (nameStart == NULL) {
nameStart = settings;
elementEnd = &nameEnd;
} else if (valueStart == NULL) {
valueStart = settings;
elementEnd = &valueEnd;
}
break;
}
unload_driver_settings(handle);
if (sawSeparator && elementEnd != NULL) {
*elementEnd = settings;
elementEnd = NULL;
}
}
if (elementEnd != NULL)
*elementEnd = settings;
if (nameStart != NULL && size_t(nameEnd - nameStart) == parameterLength
&& strncmp(parameter, nameStart, parameterLength) == 0) {
if (valueStart == NULL)
return B_NAME_NOT_FOUND;
size_t length = valueEnd - valueStart;
if (*_bufferSize > 0) {
size_t toCopy = std::min(length, *_bufferSize - 1);
memcpy(buffer, valueStart, toCopy);
buffer[toCopy] = '\0';
}
*_bufferSize = length;
return B_OK;
}
settings = nextLine;
}
return B_NAME_NOT_FOUND;
}
#endif // !_BOOT_MODE
static status_t
get_option(kernel_args* args, const char* settingsName, const char* parameter,
size_t parameterLength, char* buffer, size_t* _bufferSize)
{
#ifndef _BOOT_MODE
if (args != NULL) {
return get_option_from_kernel_args(args, settingsName, parameter,
parameterLength, buffer, _bufferSize);
}
#endif
void* handle = load_driver_settings(settingsName);
if (handle == NULL)
return B_ENTRY_NOT_FOUND;
status_t status = B_NAME_NOT_FOUND;
const char* value = get_driver_parameter(handle, parameter, NULL, NULL);
if (value != NULL) {
*_bufferSize = strlcpy(buffer, value, *_bufferSize);
status = B_OK;
}
unload_driver_settings(handle);
return status;
}
static status_t
get_option(kernel_args* args, const char* parameter, char* buffer,
size_t* _bufferSize)
{
size_t parameterLength = strlen(parameter);
status_t status = get_option(args, B_SAFEMODE_DRIVER_SETTINGS, parameter,
parameterLength, buffer, _bufferSize);
if (status != B_OK) {
// Try kernel settings file as a fall back
status = get_option(args, "kernel", parameter, parameterLength, buffer,
_bufferSize);
}
return status;
}
extern "C" bool
get_safemode_boolean(const char* parameter, bool defaultValue)
static bool
get_boolean(kernel_args* args, const char* parameter, bool defaultValue)
{
char value[16];
size_t length = sizeof(value);
if (get_safemode_option(parameter, value, &length) != B_OK)
if (get_option(args, parameter, value, &length) != B_OK)
return defaultValue;
return !strcasecmp(value, "on") || !strcasecmp(value, "true")
@ -65,6 +200,45 @@ get_safemode_boolean(const char* parameter, bool defaultValue)
}
// #pragma mark -
status_t
get_safemode_option(const char* parameter, char* buffer, size_t* _bufferSize)
{
return get_option(NULL, parameter, buffer, _bufferSize);
}
bool
get_safemode_boolean(const char* parameter, bool defaultValue)
{
return get_boolean(NULL, parameter, defaultValue);
}
#ifndef _BOOT_MODE
status_t
get_safemode_option_early(kernel_args* args, const char* parameter,
char* buffer, size_t* _bufferSize)
{
return get_option(args, parameter, buffer, _bufferSize);
}
bool
get_safemode_boolean_early(kernel_args* args, const char* parameter,
bool defaultValue)
{
return get_boolean(args, parameter, defaultValue);
}
#endif // _BOOT_MODE
// #pragma mark - syscalls