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:
@@ -11,6 +11,9 @@
|
|||||||
#include <safemode_defs.h>
|
#include <safemode_defs.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct kernel_args;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -19,6 +22,13 @@ extern "C" {
|
|||||||
status_t get_safemode_option(const char* parameter, char* buffer,
|
status_t get_safemode_option(const char* parameter, char* buffer,
|
||||||
size_t* _bufferSize);
|
size_t* _bufferSize);
|
||||||
bool get_safemode_boolean(const char* parameter, bool defaultValue);
|
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,
|
status_t _user_get_safemode_option(const char* parameter, char* buffer,
|
||||||
size_t* _bufferSize);
|
size_t* _bufferSize);
|
||||||
|
|
||||||
|
|||||||
@@ -4,59 +4,194 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <safemode.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
|
||||||
#include <safemode.h>
|
#include <boot/kernel_args.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <syscalls.h>
|
#include <syscalls.h>
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
#ifndef _BOOT_MODE
|
||||||
|
|
||||||
|
|
||||||
extern "C" status_t
|
static status_t
|
||||||
get_safemode_option(const char* parameter, char* buffer, size_t* _bufferSize)
|
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;
|
// find the settings in the kernel args
|
||||||
|
const char* settings = NULL;
|
||||||
void* handle = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS);
|
for (driver_settings_file* file = args->driver_settings;
|
||||||
if (handle != NULL) {
|
file != NULL; file = file->next) {
|
||||||
status = B_NAME_NOT_FOUND;
|
if (strcmp(settingsName, file->name) == 0) {
|
||||||
|
settings = file->buffer;
|
||||||
const char* value = get_driver_parameter(handle, parameter, NULL, NULL);
|
break;
|
||||||
if (value != NULL) {
|
|
||||||
*_bufferSize = strlcpy(buffer, value, *_bufferSize);
|
|
||||||
status = B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unload_driver_settings(handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status != B_OK) {
|
if (settings == NULL)
|
||||||
// Try kernel settings file as a fall back
|
return B_ENTRY_NOT_FOUND;
|
||||||
handle = load_driver_settings("kernel");
|
|
||||||
if (handle != NULL) {
|
// Unfortunately we can't just use parse_driver_settings_string(), since
|
||||||
const char* value = get_driver_parameter(handle, parameter, NULL,
|
// we might not have a working heap yet. So we do very limited parsing
|
||||||
NULL);
|
// ourselves.
|
||||||
if (value != NULL) {
|
const char* settingsEnd = settings + strlen(settings);
|
||||||
*_bufferSize = strlcpy(buffer, value, *_bufferSize);
|
int32 parameterLevel = 0;
|
||||||
status = B_OK;
|
|
||||||
|
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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" bool
|
static bool
|
||||||
get_safemode_boolean(const char* parameter, bool defaultValue)
|
get_boolean(kernel_args* args, const char* parameter, bool defaultValue)
|
||||||
{
|
{
|
||||||
char value[16];
|
char value[16];
|
||||||
size_t length = sizeof(value);
|
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 defaultValue;
|
||||||
|
|
||||||
return !strcasecmp(value, "on") || !strcasecmp(value, "true")
|
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
|
// #pragma mark - syscalls
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user