diff options
author | Michael Brown <mcb30@etherboot.org> | 2008-03-20 04:06:07 +0000 |
---|---|---|
committer | Michael Brown <mcb30@etherboot.org> | 2008-03-20 04:06:07 +0000 |
commit | a48b4d9948b6ffb5ca05d59ee8b04391ed24cd3b (patch) | |
tree | 3cd3e953e8d1a921cfca53e488f86bcd759742a6 /src/core/settings.c | |
parent | 7067142fb492d911588581d7620797e0a6bc706b (diff) | |
download | ipxe-a48b4d9948b6ffb5ca05d59ee8b04391ed24cd3b.tar.gz |
[Settings] Start revamping the configuration settings API.
Add the concept of an abstract configuration setting, comprising a (DHCP)
tag value and an associated byte sequence.
Add the concept of a settings namespace.
Add functions for extracting string, IPv4 address, and signed and
unsigned integer values from configuration settings (analogous to
dhcp_snprintf(), dhcp_ipv4_option(), etc.).
Update functions for parsing and formatting named/typed options to work
with new settings API.
Update NVO commands and config UI to use new settings API.
Diffstat (limited to 'src/core/settings.c')
-rw-r--r-- | src/core/settings.c | 907 |
1 files changed, 606 insertions, 301 deletions
diff --git a/src/core/settings.c b/src/core/settings.c index 1cf711d2..a5c7f816 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>. + * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -26,6 +26,7 @@ #include <assert.h> #include <gpxe/in.h> #include <gpxe/vsprintf.h> +#include <gpxe/dhcp.h> #include <gpxe/settings.h> /** @file @@ -34,48 +35,284 @@ * */ -/** Registered configuration setting types */ -static struct config_setting_type config_setting_types[0] - __table_start ( struct config_setting_type, config_setting_types ); -static struct config_setting_type config_setting_types_end[0] - __table_end ( struct config_setting_type, config_setting_types ); +/** Registered setting types */ +static struct setting_type setting_types[0] + __table_start ( struct setting_type, setting_types ); +static struct setting_type setting_types_end[0] + __table_end ( struct setting_type, setting_types ); -/** Registered configuration settings */ -static struct config_setting config_settings[0] - __table_start ( struct config_setting, config_settings ); -static struct config_setting config_settings_end[0] - __table_end ( struct config_setting, config_settings ); +/** Registered named settings */ +static struct named_setting named_settings[0] + __table_start ( struct named_setting, named_settings ); +static struct named_setting named_settings_end[0] + __table_end ( struct named_setting, named_settings ); -struct config_setting_type config_setting_type_hex __config_setting_type; +struct setting_type setting_type_hex __setting_type; /** - * Find configuration setting type + * Obtain printable version of a settings tag number + * + * @v tag Settings tag number + * @ret name String representation of the tag + */ +static inline char * setting_tag_name ( unsigned int tag ) { + static char name[8]; + + if ( DHCP_IS_ENCAP_OPT ( tag ) ) { + snprintf ( name, sizeof ( name ), "%d.%d", + DHCP_ENCAPSULATOR ( tag ), + DHCP_ENCAPSULATED ( tag ) ); + } else { + snprintf ( name, sizeof ( name ), "%d", tag ); + } + return name; +} + +/****************************************************************************** + * + * Registered settings blocks + * + ****************************************************************************** + */ + +/** List of all registered settings */ +static struct list_head all_settings = { + &interactive_settings.list, &interactive_settings.list +}; + +// Dummy routine just for testing +static int dummy_set ( struct settings *settings, unsigned int tag, + const void *data, size_t len ) { + DBGC ( settings, "Settings %p: set %s to:\n", + settings, setting_tag_name ( tag ) ); + DBGC_HD ( settings, data, len ); + return 0; +} + +// Dummy routine just for testing +static int dummy_get ( struct settings *settings, unsigned int tag, + void *data, size_t len ) { + unsigned int i; + + DBGC ( settings, "Settings %p: get %s\n", + settings, setting_tag_name ( tag ) ); + for ( i = 0 ; i < len ; i++ ) + *( ( ( uint8_t * ) data ) + i ) = i; + return ( len ? len : 8 ); +} + +struct settings_operations dummy_settings_operations = { + .set = dummy_set, + .get = dummy_get, +}; + +/** Interactively-edited settings */ +struct settings interactive_settings = { + .refcnt = NULL, + .name = "", + .list = { &all_settings, &all_settings }, + .op = &dummy_settings_operations, +}; + +/** + * Find named settings block * * @v name Name - * @ret type Configuration setting type, or NULL + * @ret settings Settings block, or NULL */ -static struct config_setting_type * -find_config_setting_type ( const char *name ) { - struct config_setting_type *type; +struct settings * find_settings ( const char *name ) { + struct settings *settings; - for ( type = config_setting_types ; type < config_setting_types_end ; - type++ ) { - if ( strcasecmp ( name, type->name ) == 0 ) - return type; + list_for_each_entry ( settings, &all_settings, list ) { + if ( strcasecmp ( name, settings->name ) == 0 ) + return settings; } return NULL; } +/****************************************************************************** + * + * Core settings routines + * + ****************************************************************************** + */ + +/** + * Get value of setting + * + * @v settings Settings block, or NULL to search all blocks + * @v tag Setting tag number + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + * + * The actual length of the setting will be returned even if + * the buffer was too small. + */ +int get_setting ( struct settings *settings, unsigned int tag, + void *data, size_t len ) { + int ret; + + if ( settings ) { + return settings->op->get ( settings, tag, data, len ); + } else { + list_for_each_entry ( settings, &all_settings, list ) { + if ( ( ret = settings->op->get ( settings, tag, + data, len ) ) >= 0 ) + return ret; + } + return -ENOENT; + } +} + +/** + * Get length of setting + * + * @v settings Settings block, or NULL to search all blocks + * @v tag Setting tag number + * @ret len Length of setting data, or negative error + * + * This function can also be used as an existence check for the + * setting. + */ +int get_setting_len ( struct settings *settings, unsigned int tag ) { + return get_setting ( settings, tag, NULL, 0 ); +} + +/** + * Get value of string setting + * + * @v settings Settings block, or NULL to search all blocks + * @v tag Setting tag number + * @v data Buffer to fill with setting string data + * @v len Length of buffer + * @ret len Length of string setting, or negative error + * + * The resulting string is guaranteed to be correctly NUL-terminated. + * The returned length will be the length of the underlying setting + * data. + */ +int get_string_setting ( struct settings *settings, unsigned int tag, + char *data, size_t len ) { + memset ( data, 0, len ); + return get_setting ( settings, tag, data, ( len - 1 ) ); +} + /** - * Find configuration setting + * Get value of IPv4 address setting + * + * @v settings Settings block, or NULL to search all blocks + * @v tag Setting tag number + * @v inp IPv4 address to fill in + * @ret len Length of setting, or negative error + */ +int get_ipv4_setting ( struct settings *settings, unsigned int tag, + struct in_addr *inp ) { + int len; + + len = get_setting ( settings, tag, inp, sizeof ( *inp ) ); + if ( len < 0 ) + return len; + if ( len != sizeof ( *inp ) ) + return -ERANGE; + return len; +} + +/** + * Get value of signed integer setting + * + * @v settings Settings block, or NULL to search all blocks + * @v tag Setting tag number + * @v value Integer value to fill in + * @ret len Length of setting, or negative error + */ +int get_int_setting ( struct settings *settings, unsigned int tag, + long *value ) { + union { + long value; + uint8_t u8[ sizeof ( long ) ]; + int8_t s8[ sizeof ( long ) ]; + } buf; + int len; + int i; + + buf.value = 0; + len = get_setting ( settings, tag, &buf, sizeof ( buf ) ); + if ( len < 0 ) + return len; + if ( len > ( int ) sizeof ( buf ) ) + return -ERANGE; + + *value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L ); + for ( i = 0 ; i < len ; i++ ) { + *value = ( ( *value << 8 ) | buf.u8[i] ); + } + + return len; +} + +/** + * Get value of unsigned integer setting + * + * @v settings Settings block, or NULL to search all blocks + * @v tag Setting tag number + * @v value Integer value to fill in + * @ret len Length of setting, or negative error + */ +int get_uint_setting ( struct settings *settings, unsigned int tag, + unsigned long *value ) { + long svalue; + int len; + + len = get_int_setting ( settings, tag, &svalue ); + if ( len < 0 ) + return len; + + *value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) ); + + return len; +} + +/****************************************************************************** + * + * Named and typed setting routines + * + ****************************************************************************** + */ + +/** + * Set value of typed setting + * + * @v settings Settings block + * @v tag Setting tag number + * @v type Settings type + * @v value Formatted setting data, or NULL + * @ret rc Return status code + */ +int set_typed_setting ( struct settings *settings, + unsigned int tag, struct setting_type *type, + const char *value ) { + + /* NULL value implies deletion. Avoid imposing the burden of + * checking for NULL values on each typed setting's setf() + * method. + */ + if ( ! value ) + return delete_setting ( settings, tag ); + + return type->setf ( settings, tag, value ); +} + +/** + * Find named setting * * @v name Name - * @ret setting Configuration setting, or NULL + * @ret setting Named setting, or NULL */ -static struct config_setting * find_config_setting ( const char *name ) { - struct config_setting *setting; +static struct named_setting * find_named_setting ( const char *name ) { + struct named_setting *setting; - for ( setting = config_settings ; setting < config_settings_end ; + for ( setting = named_settings ; setting < named_settings_end ; setting++ ) { if ( strcasecmp ( name, setting->name ) == 0 ) return setting; @@ -84,352 +321,385 @@ static struct config_setting * find_config_setting ( const char *name ) { } /** - * Find or build configuration setting + * Find setting type * * @v name Name - * @v setting Buffer to fill in with setting + * @ret type Setting type, or NULL + */ +static struct setting_type * find_setting_type ( const char *name ) { + struct setting_type *type; + + for ( type = setting_types ; type < setting_types_end ; type++ ) { + if ( strcasecmp ( name, type->name ) == 0 ) + return type; + } + return NULL; +} + +/** + * Parse setting name + * + * @v name Name of setting + * @ret settings Settings block, or NULL + * @ret tag Setting tag number + * @ret type Setting type * @ret rc Return status code * - * Find setting if it exists. If it doesn't exist, but the name is of - * the form "<num>:<type>" (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 buffer. + * Interprets a name of the form + * "[settings_name/]tag_name[:type_name]" and fills in the appropriate + * fields. */ -static int find_or_build_config_setting ( const char *name, - struct config_setting *setting ) { - struct config_setting *known_setting; +static int parse_setting_name ( const char *name, struct settings **settings, + unsigned int *tag, + struct setting_type **type ) { char tmp_name[ strlen ( name ) + 1 ]; - char *qualifier; + char *settings_name; + char *tag_name; + char *type_name; + struct named_setting *named_setting; char *tmp; /* Set defaults */ - memset ( setting, 0, sizeof ( *setting ) ); - setting->name = name; - setting->type = &config_setting_type_hex; + *settings = NULL; + *tag = 0; + *type = &setting_type_hex; - /* Strip qualifier, if present */ + /* Split name into "[settings_name/]tag_name[:type_name]" */ memcpy ( tmp_name, name, sizeof ( tmp_name ) ); - if ( ( qualifier = strchr ( tmp_name, ':' ) ) != NULL ) - *(qualifier++) = 0; + if ( ( tag_name = strchr ( tmp_name, '/' ) ) != NULL ) { + *(tag_name++) = 0; + settings_name = tmp_name; + } else { + tag_name = tmp_name; + settings_name = NULL; + } + if ( ( type_name = strchr ( tag_name, ':' ) ) != NULL ) + *(type_name++) = 0; + + /* Identify settings block, if specified */ + if ( settings_name ) { + *settings = find_settings ( settings_name ); + if ( *settings == NULL ) { + DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n", + settings_name, name ); + return -ENODEV; + } + } - /* If we recognise the name of the setting, use it */ - if ( ( known_setting = find_config_setting ( tmp_name ) ) != NULL ) { - memcpy ( setting, known_setting, sizeof ( *setting ) ); + /* Identify tag number */ + if ( ( named_setting = find_named_setting ( tag_name ) ) != NULL ) { + *tag = named_setting->tag; + *type = named_setting->type; } else { - /* Otherwise, try to interpret as a numerical setting */ - for ( tmp = tmp_name ; 1 ; tmp++ ) { - setting->tag = ( ( setting->tag << 8 ) | - strtoul ( tmp, &tmp, 0 ) ); - if ( *tmp != '.' ) + /* Unrecognised name: try to interpret as a tag number */ + tmp = tag_name; + while ( 1 ) { + *tag = ( ( *tag << 8 ) | strtoul ( tmp, &tmp, 0 ) ); + if ( *tmp == 0 ) break; + if ( *tmp != '.' ) { + DBG ( "Invalid tag number \"%s\" in \"%s\"\n", + tag_name, name ); + return -ENOENT; + } + tmp++; } - if ( *tmp != 0 ) - return -EINVAL; } - /* Apply qualifier, if present */ - if ( qualifier ) { - setting->type = find_config_setting_type ( qualifier ); - if ( ! setting->type ) - return -EINVAL; + /* Identify setting type, if specified */ + if ( type_name ) { + *type = find_setting_type ( type_name ); + if ( *type == NULL ) { + DBG ( "Invalid setting type \"%s\" in \"%s\"\n", + type_name, name ); + return -ENOTSUP; + } } return 0; } /** - * Show value of named setting + * Parse and set value of named setting * - * @v context Configuration context - * @v name Configuration setting name - * @v buf Buffer to contain value - * @v len Length of buffer - * @ret len Length of formatted value, or negative error + * @v name Name of setting + * @v value Formatted setting data, or NULL + * @ret rc Return status code */ -int show_named_setting ( struct config_context *context, const char *name, - char *buf, size_t len ) { - struct config_setting setting; +int set_named_setting ( const char *name, const char *value ) { + struct settings *settings; + unsigned int tag; + struct setting_type *type; int rc; - if ( ( rc = find_or_build_config_setting ( name, &setting ) ) != 0 ) + if ( ( rc = parse_setting_name ( name, &settings, &tag, + &type ) ) != 0 ) return rc; - return show_setting ( context, &setting, buf, len ); + if ( settings == NULL ) + return -ENODEV; + return set_typed_setting ( settings, tag, type, value ); } /** - * Set value of named setting + * Get and format value of named setting * - * @v context Configuration context - * @v name Configuration setting name - * @v value Setting value (as a string) - * @ret rc Return status code + * @v name Name of setting + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error */ -int set_named_setting ( struct config_context *context, const char *name, - const char *value ) { - struct config_setting setting; +int get_named_setting ( const char *name, char *buf, size_t len ) { + struct settings *settings; + unsigned int tag; + struct setting_type *type; int rc; - if ( ( rc = find_or_build_config_setting ( name, &setting ) ) != 0 ) + if ( ( rc = parse_setting_name ( name, &settings, &tag, + &type ) ) != 0 ) return rc; - return set_setting ( context, &setting, value ); + return get_typed_setting ( settings, tag, type, buf, len ); } +/****************************************************************************** + * + * Setting types + * + ****************************************************************************** + */ + /** - * Set value of setting + * Parse and set value of string setting * - * @v context Configuration context - * @v setting Configuration setting - * @v value Setting value (as a string), or NULL + * @v settings Settings block + * @v tag Setting tag number + * @v value Formatted setting data * @ret rc Return status code */ -int set_setting ( struct config_context *context, - struct config_setting *setting, - const char *value ) { - if ( ( ! value ) || ( ! *value ) ) { - /* Save putting deletion logic in each individual handler */ - return clear_setting ( context, setting ); - } - return setting->type->set ( context, setting, value ); +static int setf_string ( struct settings *settings, unsigned int tag, + const char *value ) { + return set_setting ( settings, tag, value, strlen ( value ) ); } /** - * Show value of string setting + * Get and format value of string setting * - * @v context Configuration context - * @v setting Configuration setting - * @v buf Buffer to contain value + * @v settings Settings block, or NULL to search all blocks + * @v tag Setting tag number + * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int show_string ( struct config_context *context, - struct config_setting *setting, +static int getf_string ( struct settings *settings, unsigned int tag, char *buf, size_t len ) { - struct dhcp_option *option; - - option = find_dhcp_option ( context->options, setting->tag ); - if ( ! option ) - return -ENODATA; - return dhcp_snprintf ( buf, len, option ); + return get_string_setting ( settings, tag, buf, len ); } +/** A string setting type */ +struct setting_type setting_type_string __setting_type = { + .name = "string", + .setf = setf_string, + .getf = getf_string, +}; + /** - * Set value of string setting + * Parse and set value of IPv4 address setting * - * @v context Configuration context - * @v setting Configuration setting - * @v value Setting value (as a string) + * @v settings Settings block + * @v tag Setting tag number + * @v value Formatted setting data * @ret rc Return status code - */ -static int set_string ( struct config_context *context, - struct config_setting *setting, - const char *value ) { - struct dhcp_option *option; + */ +static int setf_ipv4 ( struct settings *settings, unsigned int tag, + const char *value ) { + struct in_addr ipv4; - option = set_dhcp_option ( context->options, setting->tag, - value, strlen ( value ) ); - if ( ! option ) - return -ENOSPC; - return 0; + if ( inet_aton ( value, &ipv4 ) == 0 ) + return -EINVAL; + return set_setting ( settings, tag, &ipv4, sizeof ( ipv4 ) ); } -/** A string configuration setting */ -struct config_setting_type config_setting_type_string __config_setting_type = { - .name = "string", - .description = "Text string", - .show = show_string, - .set = set_string, -}; - /** - * Show value of IPv4 setting + * Get and format value of IPv4 address setting * - * @v context Configuration context - * @v setting Configuration setting - * @v buf Buffer to contain value + * @v settings Settings block, or NULL to search all blocks + * @v tag Setting tag number + * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int show_ipv4 ( struct config_context *context, - struct config_setting *setting, +static int getf_ipv4 ( struct settings *settings, unsigned int tag, char *buf, size_t len ) { - struct dhcp_option *option; struct in_addr ipv4; + int rc; - option = find_dhcp_option ( context->options, setting->tag ); - if ( ! option ) - return -ENODATA; - dhcp_ipv4_option ( option, &ipv4 ); + if ( ( rc = get_ipv4_setting ( settings, tag, &ipv4 ) ) < 0 ) + return rc; return snprintf ( buf, len, inet_ntoa ( ipv4 ) ); } -/** - * Set value of IPV4 setting - * - * @v context Configuration context - * @v setting Configuration setting - * @v value Setting value (as a string) - * @ret rc Return status code - */ -static int set_ipv4 ( struct config_context *context, - struct config_setting *setting, - const char *value ) { - struct dhcp_option *option; - struct in_addr ipv4; - - if ( inet_aton ( value, &ipv4 ) == 0 ) - return -EINVAL; - option = set_dhcp_option ( context->options, setting->tag, - &ipv4, sizeof ( ipv4 ) ); - if ( ! option ) - return -ENOSPC; - return 0; -} - -/** An IPv4 configuration setting */ -struct config_setting_type config_setting_type_ipv4 __config_setting_type = { +/** An IPv4 address setting type */ +struct setting_type setting_type_ipv4 __setting_type = { .name = "ipv4", - .description = "IPv4 address", - .show = show_ipv4, - .set = set_ipv4, + .setf = setf_ipv4, + .getf = getf_ipv4, }; /** - * Show value of integer setting + * Parse and set value of integer setting * - * @v context Configuration context - * @v setting Configuration setting - * @v buf Buffer to contain value - * @v len Length of buffer - * @ret len Length of formatted value, or negative error - */ -static int show_int ( struct config_context *context, - struct config_setting *setting, - char *buf, size_t len ) { - struct dhcp_option *option; - long num; - - option = find_dhcp_option ( context->options, setting->tag ); - if ( ! option ) - return -ENODATA; - num = dhcp_num_option ( option ); - return snprintf ( buf, len, "%ld", num ); -} - -/** - * Set value of integer setting - * - * @v context Configuration context - * @v setting Configuration setting - * @v value Setting value (as a string) - * @v size Size of integer (in bytes) + * @v settings Settings block + * @v tag Setting tag number + * @v value Formatted setting data + * @v size Integer size, in bytes * @ret rc Return status code - */ -static int set_int ( struct config_context *context, - struct config_setting *setting, - const char *value, unsigned int size ) { - struct dhcp_option *option; + */ +static int setf_int ( struct settings *settings, unsigned int tag, + const char *value, unsigned int size ) { union { uint32_t num; uint8_t bytes[4]; } u; char *endp; - /* Parse number */ - if ( ! *value ) - return -EINVAL; u.num = htonl ( strtoul ( value, &endp, 0 ) ); if ( *endp ) return -EINVAL; - - /* Set option */ - option = set_dhcp_option ( context->options, setting->tag, - &u.bytes[ sizeof ( u ) - size ], size ); - if ( ! option ) - return -ENOSPC; - return 0; + return set_setting ( settings, tag, + &u.bytes[ sizeof ( u ) - size ], size ); } /** - * Set value of 8-bit integer setting + * Parse and set value of 8-bit integer setting * - * @v context Configuration context - * @v setting Configuration setting - * @v value Setting value (as a string) - * @v size Size of integer (in bytes) + * @v settings Settings block + * @v tag Setting tag number + * @v value Formatted setting data + * @v size Integer size, in bytes * @ret rc Return status code - */ -static int set_int8 ( struct config_context *context, - struct config_setting *setting, - const char *value ) { - return set_int ( context, setting, value, 1 ); + */ +static int setf_int8 ( struct settings *settings, unsigned int tag, + const char *value ) { + return setf_int ( settings, tag, value, 1 ); } /** - * Set value of 16-bit integer setting + * Parse and set value of 16-bit integer setting * - * @v context Configuration context - * @v setting Configuration setting - * @v value Setting value (as a string) - * @v size Size of integer (in bytes) + * @v settings Settings block + * @v tag Setting tag number + * @v value Formatted setting data + * @v size Integer size, in bytes * @ret rc Return status code - */ -static int set_int16 ( struct config_context *context, - struct config_setting *setting, + */ +static int setf_int16 ( struct settings *settings, unsigned int tag, const char *value ) { - return set_int ( context, setting, value, 2 ); + return setf_int ( settings, tag, value, 2 ); } /** - * Set value of 32-bit integer setting + * Parse and set value of 32-bit integer setting * - * @v context Configuration context - * @v setting Configuration setting - * @v value Setting value (as a string) - * @v size Size of integer (in bytes) + * @v settings Settings block + * @v tag Setting tag number + * @v value Formatted setting data + * @v size Integer size, in bytes * @ret rc Return status code - */ -static int set_int32 ( struct config_context *context, - struct config_setting *setting, + */ +static int setf_int32 ( struct settings *settings, unsigned int tag, const char *value ) { - return set_int ( context, setting, value, 4 ); + return setf_int ( settings, tag, value, 4 ); +} + +/** + * Get and format value of signed integer setting + * + * @v settings Settings block, or NULL to search all blocks + * @v tag Setting tag number + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int getf_int ( struct settings *settings, unsigned int tag, + char *buf, size_t len ) { + long value; + int rc; + + if ( ( rc = get_int_setting ( settings, tag, &value ) ) < 0 ) + return rc; + return snprintf ( buf, len, "%ld", value ); +} + +/** + * Get and format value of unsigned integer setting + * + * @v settings Settings block, or NULL to search all blocks + * @v tag Setting tag number + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int getf_uint ( struct settings *settings, unsigned int tag, + char *buf, size_t len ) { + unsigned long value; + int rc; + + if ( ( rc = get_uint_setting ( settings, tag, &value ) ) < 0 ) + return rc; + return snprintf ( buf, len, "%#lx", value ); } -/** An 8-bit integer configuration setting */ -struct config_setting_type config_setting_type_int8 __config_setting_type = { +/** A signed 8-bit integer setting type */ +struct setting_type setting_type_int8 __setting_type = { .name = "int8", - .description = "8-bit integer", - .show = show_int, - .set = set_int8, + .setf = setf_int8, + .getf = getf_int, }; -/** A 16-bit integer configuration setting */ -struct config_setting_type config_setting_type_int16 __config_setting_type = { +/** A signed 16-bit integer setting type */ +struct setting_type setting_type_int16 __setting_type = { .name = "int16", - .description = "16-bit integer", - .show = show_int, - .set = set_int16, + .setf = setf_int16, + .getf = getf_int, }; -/** A 32-bit integer configuration setting */ -struct config_setting_type config_setting_type_int32 __config_setting_type = { +/** A signed 32-bit integer setting type */ +struct setting_type setting_type_int32 __setting_type = { .name = "int32", - .description = "32-bit integer", - .show = show_int, - .set = set_int32, + .setf = setf_int32, + .getf = getf_int, +}; + +/** An unsigned 8-bit integer setting type */ +struct setting_type setting_type_uint8 __setting_type = { + .name = "uint8", + .setf = setf_int8, + .getf = getf_uint, +}; + +/** An unsigned 16-bit integer setting type */ +struct setting_type setting_type_uint16 __setting_type = { + .name = "uint16", + .setf = setf_int16, + .getf = getf_uint, +}; + +/** An unsigned 32-bit integer setting type */ +struct setting_type setting_type_uint32 __setting_type = { + .name = "uint32", + .setf = setf_int32, + .getf = getf_uint, }; /** - * Set value of hex-string setting + * Parse and set value of hex string setting * - * @v context Configuration context - * @v setting Configuration setting - * @v value Setting value (as a string) + * @v settings Settings block + * @v tag Setting tag number + * @v value Formatted setting data * @ret rc Return status code - */ -static int set_hex ( struct config_context *context, - struct config_setting *setting, - const char *value ) { - struct dhcp_option *option; + */ +static int setf_hex ( struct settings *settings, unsigned int tag, + const char *value ) { char *ptr = ( char * ) value; uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */ unsigned int len = 0; @@ -438,11 +708,7 @@ static int set_hex ( struct config_context *context, bytes[len++] = strtoul ( ptr, &ptr, 16 ); switch ( *ptr ) { case '\0' : - option = set_dhcp_option ( context->options, - setting->tag, bytes, len ); - if ( ! option ) - return -ENOSPC; - return 0; + return set_setting ( settings, tag, bytes, len ); case ':' : ptr++; break; @@ -453,83 +719,122 @@ static int set_hex ( struct config_context *context, } /** - * Show value of hex-string setting + * Get and format value of hex string setting * - * @v context Configuration context - * @v setting Configuration setting - * @v buf Buffer to contain value + * @v settings Settings block, or NULL to search all blocks + * @v tag Setting tag number + * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int show_hex ( struct config_context *context, - struct config_setting *setting, +static int getf_hex ( struct settings *settings, unsigned int tag, char *buf, size_t len ) { - struct dhcp_option *option; + int raw_len; + int check_len; int used = 0; int i; - option = find_dhcp_option ( context->options, setting->tag ); - if ( ! option ) - return -ENODATA; + raw_len = get_setting_len ( settings, tag ); + if ( raw_len < 0 ) + return raw_len; - for ( i = 0 ; i < option->len ; i++ ) { - used += ssnprintf ( ( buf + used ), ( len - used ), - "%s%02x", ( used ? ":" : "" ), - option->data.bytes[i] ); + { + uint8_t raw[raw_len]; + + check_len = get_setting ( settings, tag, raw, sizeof ( raw ) ); + assert ( check_len == raw_len ); + + if ( len ) + buf[0] = 0; /* Ensure that a terminating NUL exists */ + for ( i = 0 ; i < raw_len ; i++ ) { + used += ssnprintf ( ( buf + used ), ( len - used ), + "%s%02x", ( used ? ":" : "" ), + raw[i] ); + } + return used; } - return used; } -/** A hex-string configuration setting */ -struct config_setting_type config_setting_type_hex __config_setting_type = { +/** A hex-string setting */ +struct setting_type setting_type_hex __setting_type = { .name = "hex", - .description = "Hex string", - .show = show_hex, - .set = set_hex, + .setf = setf_hex, + .getf = getf_hex, }; +/****************************************************************************** + * + * Named settings + * + ****************************************************************************** + */ + /** Some basic setting definitions */ -struct config_setting basic_config_settings[] __config_setting = { +struct named_setting basic_named_settings[] __named_setting = { { .name = "ip", - .description = "IP address of this machine (e.g. 192.168.0.1)", + .description = "IPv4 address of this interface", .tag = DHCP_EB_YIADDR, - .type = &config_setting_type_ipv4, + .type = &setting_type_ipv4, + }, + { + .name = "subnet-mask", + .description = "IPv4 subnet mask", + .tag = DHCP_SUBNET_MASK, + .type = &setting_type_ipv4, + }, + { + .name = "routers", + .description = "Default gateway", + .tag = DHCP_ROUTERS, + .type = &setting_type_ipv4, + }, + { + .name = "domain-name-servers", + .description = "DNS server", + .tag = DHCP_DNS_SERVERS, + .type = &setting_type_ipv4, }, { .name = "hostname", .description = "Host name of this machine", .tag = DHCP_HOST_NAME, - .type = &config_setting_type_string, + .type = &setting_type_string, + }, + { + .name = "filename", + .description = "Boot filename", + .tag = DHCP_BOOTFILE_NAME, + .type = &setting_type_string, + }, + { + .name = "root-path", + .description = "NFS/iSCSI root path", + .tag = DHCP_ROOT_PATH, + .type = &setting_type_string, }, { .name = "username", - .description = "User name for authentication to servers", + .description = "User name for authentication", .tag = DHCP_EB_USERNAME, - .type = &config_setting_type_string, + .type = &setting_type_string, }, { .name = "password", - .description = "Password for authentication to servers", + .description = "Password for authentication", .tag = DHCP_EB_PASSWORD, - .type = &config_setting_type_string, + .type = &setting_type_string, }, { - .name = "root-path", - .description = "NFS/iSCSI root path", - .tag = DHCP_ROOT_PATH, - .type = &config_setting_type_string, + .name = "initiator-iqn", + .description = "iSCSI initiator name", + .tag = DHCP_ISCSI_INITIATOR_IQN, + .type = &setting_type_string, }, { .name = "priority", .description = "Priority of these options", .tag = DHCP_EB_PRIORITY, - .type = &config_setting_type_int8, + .type = &setting_type_int8, }, - { - .name = "initiator-iqn", - .description = "iSCSI qualified name of this machine", - .tag = DHCP_ISCSI_INITIATOR_IQN, - .type = &config_setting_type_string, - } }; |