diff --git a/src/core/settings.c b/src/core/settings.c new file mode 100644 index 00000000..4df491fb --- /dev/null +++ b/src/core/settings.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2006 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +/** @file + * + * Configuration settings + * + */ + +/** Registered configuration setting types */ +static struct config_setting_type +config_setting_types[0] __table_start ( config_setting_types ); +static struct config_setting_type +config_setting_types_end[0] __table_end ( config_setting_types ); + +/** Registered configuration settings */ +static struct config_setting +config_settings[0] __table_start ( config_settings ); +static struct config_setting +config_settings_end[0] __table_end ( config_settings ); + +/** + * Find configuration setting type + * + * @v name Name + * @ret type Configuration setting type, or NULL + */ +static struct config_setting_type * +find_config_setting_type ( const char *name ) { + struct config_setting_type *type; + + for ( type = config_setting_types ; type < config_setting_types_end ; + type++ ) { + if ( strcmp ( name, type->name ) == 0 ) + return type; + } + return NULL; +} + +/** + * Find configuration setting + * + * @v name Name + * @ret setting Configuration setting, or NULL + */ +static struct config_setting * find_config_setting ( const char *name ) { + struct config_setting *setting; + + for ( setting = config_settings ; setting < config_settings_end ; + setting++ ) { + if ( strcmp ( name, setting->name ) == 0 ) + return setting; + } + return NULL; +} + +/** + * Find or build configuration setting + * + * @v name Name + * @v tmp_setting Temporary buffer for constructing a setting + * @ret setting Configuration setting, or NULL + * + * Find setting if it exists. If it doesn't exist, but the name is of + * the form "." (e.g. "12.string"), then construct a + * setting for that tag and data type, and return it. The constructed + * setting will be placed in the temporary buffer. + */ +static struct config_setting * +find_or_build_config_setting ( const char *name, + struct config_setting *tmp_setting ) { + struct config_setting *setting; + char *separator; + + /* Look in the list of registered settings first */ + setting = find_config_setting ( name ); + if ( setting ) + return setting; + + /* If name is of the form ".", try to construct a setting */ + setting = tmp_setting; + memset ( setting, 0, sizeof ( *setting ) ); + setting->name = name; + setting->tag = strtoul ( name, &separator, 10 ); + if ( *separator != '.' ) + return NULL; + setting->type = find_config_setting_type ( separator + 1 ); + if ( ! setting->type ) + return NULL; + return setting; +} + +/** Show value of setting + * + * @v context Configuration context + * @v name Configuration setting name + * @ret value Setting value (as a string), or NULL + */ +const char * ( show_setting ) ( struct config_context *context, + const char *name ) { + struct config_setting *setting; + struct config_setting tmp_setting; + + setting = find_or_build_config_setting ( name, &tmp_setting ); + if ( ! setting ) + return NULL; + return setting->type->show ( context, setting ); +} + +/** Set value of setting + * + * @v context Configuration context + * @v name Configuration setting name + * @v value Setting value (as a string) + * @ret rc Return status code + */ +int ( set_setting ) ( struct config_context *context, const char *name, + const char *value ) { + struct config_setting *setting; + struct config_setting tmp_setting; + + setting = find_or_build_config_setting ( name, &tmp_setting ); + if ( ! setting ) + return -ENOENT; + return setting->type->set ( context, setting, value ); +} diff --git a/src/include/gpxe/settings.h b/src/include/gpxe/settings.h new file mode 100644 index 00000000..f05805f2 --- /dev/null +++ b/src/include/gpxe/settings.h @@ -0,0 +1,103 @@ +#ifndef _GPXE_SETTINGS_H +#define _GPXE_SETTINGS_H + +/** @file + * + * Configuration settings + * + */ + +#include +#include +#include + +struct config_setting; + +/** + * A configuration context + * + * This identifies the context within which settings are inspected and + * changed. For example, the context might be global, or might be + * restricted to the settings stored in NVS on a particular device. + */ +struct config_context { + /** DHCP options block, or NULL + * + * If NULL, all registered DHCP options blocks will be used. + */ + struct dhcp_option_block *options; +}; + +/** + * A configuration setting type + * + * This represents a type of configuration setting (e.g. string, IPv4 + * address, etc.). + */ +struct config_setting_type { + /** Name + * + * This is the name exposed to the user (e.g. "string"). + */ + const char *name; + /** Show value of setting + * + * @v context Configuration context + * @v setting Configuration setting + * @ret value Setting value (as a string), or NULL + */ + const char * ( * show ) ( struct config_context *context, + struct config_setting *setting ); + /** Set value of setting + * + * @v context Configuration context + * @v setting Configuration setting + * @v value Setting value (as a string) + * @ret rc Return status code + */ + int ( * set ) ( struct config_context *context, + struct config_setting *setting, + const char *value ); +}; + +/** Declare a configuration setting type */ +#define __config_setting_type __table ( config_setting_types, 01 ) + +/** + * A configuration setting + * + * This represents a single configuration setting (e.g. "hostname"). + */ +struct config_setting { + /** Name + * + * This is the human-readable name for the setting. Where + * possible, it should match the name used in dhcpd.conf (see + * dhcp-options(5)). + */ + const char *name; + /** DHCP option tag + * + * This is the DHCP tag used to identify the option in DHCP + * packets and stored option blocks. + */ + unsigned int tag; + /** Configuration setting type + * + * This identifies the type of setting (e.g. string, IPv4 + * address, etc.). + */ + struct config_setting_type *type; +}; + +/** Declare a configuration setting */ +#define __config_setting __table ( config_settings, 01 ) + +/* Function prototypes */ + +extern const char * ( show_setting ) ( struct config_context *context, + const char *name ); +extern int ( set_setting ) ( struct config_context *context, const char *name, + const char *value ); + +#endif /* _GPXE_SETTINGS_H */