diff options
Diffstat (limited to 'gpxe/src/core/settings.c')
-rw-r--r-- | gpxe/src/core/settings.c | 1456 |
1 files changed, 0 insertions, 1456 deletions
diff --git a/gpxe/src/core/settings.c b/gpxe/src/core/settings.c deleted file mode 100644 index 7d83101c..00000000 --- a/gpxe/src/core/settings.c +++ /dev/null @@ -1,1456 +0,0 @@ -/* - * 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 - * 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. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <stdint.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <strings.h> -#include <byteswap.h> -#include <errno.h> -#include <assert.h> -#include <gpxe/in.h> -#include <gpxe/vsprintf.h> -#include <gpxe/dhcp.h> -#include <gpxe/uuid.h> -#include <gpxe/uri.h> -#include <gpxe/settings.h> - -/** @file - * - * Configuration settings - * - */ - -/****************************************************************************** - * - * Generic settings blocks - * - ****************************************************************************** - */ - -/** - * A generic setting - * - */ -struct generic_setting { - /** List of generic settings */ - struct list_head list; - /** Setting */ - struct setting setting; - /** Size of setting name */ - size_t name_len; - /** Size of setting data */ - size_t data_len; -}; - -/** - * Get generic setting name - * - * @v generic Generic setting - * @ret name Generic setting name - */ -static inline void * generic_setting_name ( struct generic_setting *generic ) { - return ( ( ( void * ) generic ) + sizeof ( *generic ) ); -} - -/** - * Get generic setting data - * - * @v generic Generic setting - * @ret data Generic setting data - */ -static inline void * generic_setting_data ( struct generic_setting *generic ) { - return ( ( ( void * ) generic ) + sizeof ( *generic ) + - generic->name_len ); -} - -/** - * Find generic setting - * - * @v generics Generic settings block - * @v setting Setting to find - * @ret generic Generic setting, or NULL - */ -static struct generic_setting * -find_generic_setting ( struct generic_settings *generics, - struct setting *setting ) { - struct generic_setting *generic; - - list_for_each_entry ( generic, &generics->list, list ) { - if ( setting_cmp ( &generic->setting, setting ) == 0 ) - return generic; - } - return NULL; -} - -/** - * Store value of generic setting - * - * @v settings Settings block - * @v setting Setting to store - * @v data Setting data, or NULL to clear setting - * @v len Length of setting data - * @ret rc Return status code - */ -int generic_settings_store ( struct settings *settings, - struct setting *setting, - const void *data, size_t len ) { - struct generic_settings *generics = - container_of ( settings, struct generic_settings, settings ); - struct generic_setting *old; - struct generic_setting *new = NULL; - size_t name_len; - - /* Identify existing generic setting, if any */ - old = find_generic_setting ( generics, setting ); - - /* Create new generic setting, if required */ - if ( len ) { - /* Allocate new generic setting */ - name_len = ( strlen ( setting->name ) + 1 ); - new = zalloc ( sizeof ( *new ) + name_len + len ); - if ( ! new ) - return -ENOMEM; - - /* Populate new generic setting */ - new->name_len = name_len; - new->data_len = len; - memcpy ( &new->setting, setting, sizeof ( new->setting ) ); - new->setting.name = generic_setting_name ( new ); - memcpy ( generic_setting_name ( new ), - setting->name, name_len ); - memcpy ( generic_setting_data ( new ), data, len ); - } - - /* Delete existing generic setting, if any */ - if ( old ) { - list_del ( &old->list ); - free ( old ); - } - - /* Add new setting to list, if any */ - if ( new ) - list_add ( &new->list, &generics->list ); - - return 0; -} - -/** - * Fetch value of generic setting - * - * @v settings Settings block - * @v setting Setting to fetch - * @v data Buffer to fill with setting data - * @v len Length of buffer - * @ret len Length of setting data, or negative error - */ -int generic_settings_fetch ( struct settings *settings, - struct setting *setting, - void *data, size_t len ) { - struct generic_settings *generics = - container_of ( settings, struct generic_settings, settings ); - struct generic_setting *generic; - - /* Find generic setting */ - generic = find_generic_setting ( generics, setting ); - if ( ! generic ) - return -ENOENT; - - /* Copy out generic setting data */ - if ( len > generic->data_len ) - len = generic->data_len; - memcpy ( data, generic_setting_data ( generic ), len ); - return generic->data_len; -} - -/** - * Clear generic settings block - * - * @v settings Settings block - */ -void generic_settings_clear ( struct settings *settings ) { - struct generic_settings *generics = - container_of ( settings, struct generic_settings, settings ); - struct generic_setting *generic; - struct generic_setting *tmp; - - list_for_each_entry_safe ( generic, tmp, &generics->list, list ) { - list_del ( &generic->list ); - free ( generic ); - } - assert ( list_empty ( &generics->list ) ); -} - -/** Generic settings operations */ -struct settings_operations generic_settings_operations = { - .store = generic_settings_store, - .fetch = generic_settings_fetch, - .clear = generic_settings_clear, -}; - -/****************************************************************************** - * - * Registered settings blocks - * - ****************************************************************************** - */ - -/** Root generic settings block */ -struct generic_settings generic_settings_root = { - .settings = { - .refcnt = NULL, - .name = "", - .siblings = - LIST_HEAD_INIT ( generic_settings_root.settings.siblings ), - .children = - LIST_HEAD_INIT ( generic_settings_root.settings.children ), - .op = &generic_settings_operations, - }, - .list = LIST_HEAD_INIT ( generic_settings_root.list ), -}; - -/** Root settings block */ -#define settings_root generic_settings_root.settings - -/** - * Find child named settings block - * - * @v parent Parent settings block - * @v name Name within this parent - * @ret settings Settings block, or NULL - */ -static struct settings * find_child_settings ( struct settings *parent, - const char *name ) { - struct settings *settings; - - /* Treat empty name as meaning "this block" */ - if ( ! *name ) - return parent; - - /* Look for child with matching name */ - list_for_each_entry ( settings, &parent->children, siblings ) { - if ( strcmp ( settings->name, name ) == 0 ) - return settings; - } - - return NULL; -} - -/** - * Find or create child named settings block - * - * @v parent Parent settings block - * @v name Name within this parent - * @ret settings Settings block, or NULL - */ -static struct settings * autovivify_child_settings ( struct settings *parent, - const char *name ) { - struct { - struct generic_settings generic; - char name[ strlen ( name ) + 1 /* NUL */ ]; - } *new_child; - struct settings *settings; - - /* Return existing settings, if existent */ - if ( ( settings = find_child_settings ( parent, name ) ) != NULL ) - return settings; - - /* Create new generic settings block */ - new_child = zalloc ( sizeof ( *new_child ) ); - if ( ! new_child ) { - DBGC ( parent, "Settings %p could not create child %s\n", - parent, name ); - return NULL; - } - memcpy ( new_child->name, name, sizeof ( new_child->name ) ); - generic_settings_init ( &new_child->generic, NULL, new_child->name ); - settings = &new_child->generic.settings; - register_settings ( settings, parent ); - return settings; -} - -/** - * Return settings block name (for debug only) - * - * @v settings Settings block - * @ret name Settings block name - */ -static const char * settings_name ( struct settings *settings ) { - static char buf[64]; - char tmp[ sizeof ( buf ) ]; - int count; - - for ( count = 0 ; settings ; settings = settings->parent ) { - memcpy ( tmp, buf, sizeof ( tmp ) ); - snprintf ( buf, sizeof ( buf ), "%s%c%s", settings->name, - ( count++ ? '.' : '\0' ), tmp ); - } - return ( buf + 1 ); -} - -/** - * Parse settings block name - * - * @v name Name - * @v get_child Function to find or create child settings block - * @ret settings Settings block, or NULL - */ -static struct settings * -parse_settings_name ( const char *name, - struct settings * ( * get_child ) ( struct settings *, - const char * ) ) { - struct settings *settings = &settings_root; - char name_copy[ strlen ( name ) + 1 ]; - char *subname; - char *remainder; - - /* Create modifiable copy of name */ - memcpy ( name_copy, name, sizeof ( name_copy ) ); - remainder = name_copy; - - /* Parse each name component in turn */ - while ( remainder ) { - struct net_device *netdev; - - subname = remainder; - remainder = strchr ( subname, '.' ); - if ( remainder ) - *(remainder++) = '\0'; - - /* Special case "netX" root settings block */ - if ( ( subname == name_copy ) && ! strcmp ( subname, "netX" ) && - ( ( netdev = last_opened_netdev() ) != NULL ) ) - settings = get_child ( settings, netdev->name ); - else - settings = get_child ( settings, subname ); - - if ( ! settings ) - break; - } - - return settings; -} - -/** - * Find named settings block - * - * @v name Name - * @ret settings Settings block, or NULL - */ -struct settings * find_settings ( const char *name ) { - - return parse_settings_name ( name, find_child_settings ); -} - -/** - * Apply all settings - * - * @ret rc Return status code - */ -static int apply_settings ( void ) { - struct settings_applicator *applicator; - int rc; - - /* Call all settings applicators */ - for_each_table_entry ( applicator, SETTINGS_APPLICATORS ) { - if ( ( rc = applicator->apply() ) != 0 ) { - DBG ( "Could not apply settings using applicator " - "%p: %s\n", applicator, strerror ( rc ) ); - return rc; - } - } - - return 0; -} - -/** - * Reprioritise settings - * - * @v settings Settings block - * - * Reorders the settings block amongst its siblings according to its - * priority. - */ -static void reprioritise_settings ( struct settings *settings ) { - struct settings *parent = settings->parent; - long priority; - struct settings *tmp; - long tmp_priority; - - /* Stop when we reach the top of the tree */ - if ( ! parent ) - return; - - /* Read priority, if present */ - priority = fetch_intz_setting ( settings, &priority_setting ); - - /* Remove from siblings list */ - list_del ( &settings->siblings ); - - /* Reinsert after any existing blocks which have a higher priority */ - list_for_each_entry ( tmp, &parent->children, siblings ) { - tmp_priority = fetch_intz_setting ( tmp, &priority_setting ); - if ( priority > tmp_priority ) - break; - } - list_add_tail ( &settings->siblings, &tmp->siblings ); - - /* Recurse up the tree */ - reprioritise_settings ( parent ); -} - -/** - * Register settings block - * - * @v settings Settings block - * @v parent Parent settings block, or NULL - * @ret rc Return status code - */ -int register_settings ( struct settings *settings, struct settings *parent ) { - struct settings *old_settings; - - /* NULL parent => add to settings root */ - assert ( settings != NULL ); - if ( parent == NULL ) - parent = &settings_root; - - /* Remove any existing settings with the same name */ - if ( ( old_settings = find_child_settings ( parent, settings->name ) )) - unregister_settings ( old_settings ); - - /* Add to list of settings */ - ref_get ( settings->refcnt ); - ref_get ( parent->refcnt ); - settings->parent = parent; - list_add_tail ( &settings->siblings, &parent->children ); - DBGC ( settings, "Settings %p (\"%s\") registered\n", - settings, settings_name ( settings ) ); - - /* Fix up settings priority */ - reprioritise_settings ( settings ); - - /* Apply potentially-updated settings */ - apply_settings(); - - return 0; -} - -/** - * Unregister settings block - * - * @v settings Settings block - */ -void unregister_settings ( struct settings *settings ) { - - DBGC ( settings, "Settings %p (\"%s\") unregistered\n", - settings, settings_name ( settings ) ); - - /* Remove from list of settings */ - ref_put ( settings->refcnt ); - ref_put ( settings->parent->refcnt ); - settings->parent = NULL; - list_del ( &settings->siblings ); - - /* Apply potentially-updated settings */ - apply_settings(); -} - -/****************************************************************************** - * - * Core settings routines - * - ****************************************************************************** - */ - -/** - * Store value of setting - * - * @v settings Settings block, or NULL - * @v setting Setting to store - * @v data Setting data, or NULL to clear setting - * @v len Length of setting data - * @ret rc Return status code - */ -int store_setting ( struct settings *settings, struct setting *setting, - const void *data, size_t len ) { - int rc; - - /* NULL settings implies storing into the global settings root */ - if ( ! settings ) - settings = &settings_root; - - /* Sanity check */ - if ( ! settings->op->store ) - return -ENOTSUP; - - /* Store setting */ - if ( ( rc = settings->op->store ( settings, setting, - data, len ) ) != 0 ) - return rc; - - /* Reprioritise settings if necessary */ - if ( setting_cmp ( setting, &priority_setting ) == 0 ) - reprioritise_settings ( settings ); - - /* If these settings are registered, apply potentially-updated - * settings - */ - for ( ; settings ; settings = settings->parent ) { - if ( settings == &settings_root ) { - if ( ( rc = apply_settings() ) != 0 ) - return rc; - break; - } - } - - return 0; -} - -/** - * Fetch value of setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @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 fetch_setting ( struct settings *settings, struct setting *setting, - void *data, size_t len ) { - struct settings *child; - int ret; - - /* Avoid returning uninitialised data on error */ - memset ( data, 0, len ); - - /* NULL settings implies starting at the global settings root */ - if ( ! settings ) - settings = &settings_root; - - /* Sanity check */ - if ( ! settings->op->fetch ) - return -ENOTSUP; - - /* Try this block first */ - if ( ( ret = settings->op->fetch ( settings, setting, - data, len ) ) >= 0 ) - return ret; - - /* Recurse into each child block in turn */ - list_for_each_entry ( child, &settings->children, siblings ) { - if ( ( ret = fetch_setting ( child, setting, - data, len ) ) >= 0 ) - return ret; - } - - return -ENOENT; -} - -/** - * Fetch length of setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @ret len Length of setting data, or negative error - * - * This function can also be used as an existence check for the - * setting. - */ -int fetch_setting_len ( struct settings *settings, struct setting *setting ) { - return fetch_setting ( settings, setting, NULL, 0 ); -} - -/** - * Fetch value of string setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @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 fetch_string_setting ( struct settings *settings, struct setting *setting, - char *data, size_t len ) { - memset ( data, 0, len ); - return fetch_setting ( settings, setting, data, - ( ( len > 0 ) ? ( len - 1 ) : 0 ) ); -} - -/** - * Fetch value of string setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v data Buffer to allocate and fill with setting string data - * @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. The caller is responsible for eventually freeing the - * allocated buffer. - */ -int fetch_string_setting_copy ( struct settings *settings, - struct setting *setting, - char **data ) { - int len; - int check_len = 0; - - len = fetch_setting_len ( settings, setting ); - if ( len < 0 ) - return len; - - *data = malloc ( len + 1 ); - if ( ! *data ) - return -ENOMEM; - - check_len = fetch_string_setting ( settings, setting, *data, - ( len + 1 ) ); - assert ( check_len == len ); - return len; -} - -/** - * Fetch value of IPv4 address setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v inp IPv4 address to fill in - * @ret len Length of setting, or negative error - */ -int fetch_ipv4_setting ( struct settings *settings, struct setting *setting, - struct in_addr *inp ) { - int len; - - len = fetch_setting ( settings, setting, inp, sizeof ( *inp ) ); - if ( len < 0 ) - return len; - if ( len < ( int ) sizeof ( *inp ) ) - return -ERANGE; - return len; -} - -/** - * Fetch value of signed integer setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v value Integer value to fill in - * @ret len Length of setting, or negative error - */ -int fetch_int_setting ( struct settings *settings, struct setting *setting, - long *value ) { - union { - uint8_t u8[ sizeof ( long ) ]; - int8_t s8[ sizeof ( long ) ]; - } buf; - int len; - int i; - - /* Avoid returning uninitialised data on error */ - *value = 0; - - /* Fetch raw (network-ordered, variable-length) setting */ - len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) ); - if ( len < 0 ) - return len; - if ( len > ( int ) sizeof ( buf ) ) - return -ERANGE; - - /* Convert to host-ordered signed long */ - *value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L ); - for ( i = 0 ; i < len ; i++ ) { - *value = ( ( *value << 8 ) | buf.u8[i] ); - } - - return len; -} - -/** - * Fetch value of unsigned integer setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v value Integer value to fill in - * @ret len Length of setting, or negative error - */ -int fetch_uint_setting ( struct settings *settings, struct setting *setting, - unsigned long *value ) { - long svalue; - int len; - - /* Avoid returning uninitialised data on error */ - *value = 0; - - /* Fetch as a signed long */ - len = fetch_int_setting ( settings, setting, &svalue ); - if ( len < 0 ) - return len; - - /* Mask off sign-extended bits */ - assert ( len <= ( int ) sizeof ( long ) ); - *value = ( svalue & ( -1UL >> ( 8 * ( sizeof ( long ) - len ) ) ) ); - - return len; -} - -/** - * Fetch value of signed integer setting, or zero - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @ret value Setting value, or zero - */ -long fetch_intz_setting ( struct settings *settings, struct setting *setting ){ - long value; - - fetch_int_setting ( settings, setting, &value ); - return value; -} - -/** - * Fetch value of unsigned integer setting, or zero - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @ret value Setting value, or zero - */ -unsigned long fetch_uintz_setting ( struct settings *settings, - struct setting *setting ) { - unsigned long value; - - fetch_uint_setting ( settings, setting, &value ); - return value; -} - -/** - * Fetch value of UUID setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v uuid UUID to fill in - * @ret len Length of setting, or negative error - */ -int fetch_uuid_setting ( struct settings *settings, struct setting *setting, - union uuid *uuid ) { - int len; - - len = fetch_setting ( settings, setting, uuid, sizeof ( *uuid ) ); - if ( len < 0 ) - return len; - if ( len != sizeof ( *uuid ) ) - return -ERANGE; - return len; -} - -/** - * Clear settings block - * - * @v settings Settings block - */ -void clear_settings ( struct settings *settings ) { - if ( settings->op->clear ) - settings->op->clear ( settings ); -} - -/** - * Compare two settings - * - * @v a Setting to compare - * @v b Setting to compare - * @ret 0 Settings are the same - * @ret non-zero Settings are not the same - */ -int setting_cmp ( struct setting *a, struct setting *b ) { - - /* If the settings have tags, compare them */ - if ( a->tag && ( a->tag == b->tag ) ) - return 0; - - /* Otherwise, if the settings have names, compare them */ - if ( a->name && b->name && a->name[0] ) - return strcmp ( a->name, b->name ); - - /* Otherwise, return a non-match */ - return ( ! 0 ); -} - -/****************************************************************************** - * - * Formatted setting routines - * - ****************************************************************************** - */ - -/** - * Store value of typed setting - * - * @v settings Settings block - * @v setting Setting to store - * @v type Settings type - * @v value Formatted setting data, or NULL - * @ret rc Return status code - */ -int storef_setting ( struct settings *settings, struct setting *setting, - const char *value ) { - - /* NULL value implies deletion. Avoid imposing the burden of - * checking for NULL values on each typed setting's storef() - * method. - */ - if ( ! value ) - return delete_setting ( settings, setting ); - - return setting->type->storef ( settings, setting, value ); -} - -/** - * Find named setting - * - * @v name Name - * @ret setting Named setting, or NULL - */ -static struct setting * find_setting ( const char *name ) { - struct setting *setting; - - for_each_table_entry ( setting, SETTINGS ) { - if ( strcmp ( name, setting->name ) == 0 ) - return setting; - } - return NULL; -} - -/** - * Parse setting name as tag number - * - * @v name Name - * @ret tag Tag number, or 0 if not a valid number - */ -static unsigned int parse_setting_tag ( const char *name ) { - char *tmp = ( ( char * ) name ); - unsigned int tag = 0; - - while ( 1 ) { - tag = ( ( tag << 8 ) | strtoul ( tmp, &tmp, 0 ) ); - if ( *tmp == 0 ) - return tag; - if ( *tmp != '.' ) - return 0; - tmp++; - } -} - -/** - * Find setting type - * - * @v name Name - * @ret type Setting type, or NULL - */ -static struct setting_type * find_setting_type ( const char *name ) { - struct setting_type *type; - - for_each_table_entry ( type, SETTING_TYPES ) { - if ( strcmp ( name, type->name ) == 0 ) - return type; - } - return NULL; -} - -/** - * Parse setting name - * - * @v name Name of setting - * @v get_child Function to find or create child settings block - * @v settings Settings block to fill in - * @v setting Setting to fill in - * @v tmp_name Buffer for copy of setting name - * @ret rc Return status code - * - * Interprets a name of the form - * "[settings_name/]tag_name[:type_name]" and fills in the appropriate - * fields. - * - * The @c tmp_name buffer must be large enough to hold a copy of the - * setting name. - */ -static int -parse_setting_name ( const char *name, - struct settings * ( * get_child ) ( struct settings *, - const char * ), - struct settings **settings, struct setting *setting, - char *tmp_name ) { - char *settings_name; - char *setting_name; - char *type_name; - struct setting *named_setting; - - /* Set defaults */ - *settings = &settings_root; - memset ( setting, 0, sizeof ( *setting ) ); - setting->name = ""; - setting->type = &setting_type_string; - - /* Split name into "[settings_name/]setting_name[:type_name]" */ - strcpy ( tmp_name, name ); - if ( ( setting_name = strchr ( tmp_name, '/' ) ) != NULL ) { - *(setting_name++) = 0; - settings_name = tmp_name; - } else { - setting_name = tmp_name; - settings_name = NULL; - } - if ( ( type_name = strchr ( setting_name, ':' ) ) != NULL ) - *(type_name++) = 0; - - /* Identify settings block, if specified */ - if ( settings_name ) { - *settings = parse_settings_name ( settings_name, get_child ); - if ( *settings == NULL ) { - DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n", - settings_name, name ); - return -ENODEV; - } - } - - /* Identify setting */ - if ( ( named_setting = find_setting ( setting_name ) ) != NULL ) { - /* Matches a defined named setting; use that setting */ - memcpy ( setting, named_setting, sizeof ( *setting ) ); - } else if ( ( setting->tag = parse_setting_tag ( setting_name ) ) !=0){ - /* Is a valid numeric tag; use the tag */ - setting->tag |= (*settings)->tag_magic; - } else { - /* Use the arbitrary name */ - setting->name = setting_name; - } - - /* Identify setting type, if specified */ - if ( type_name ) { - setting->type = find_setting_type ( type_name ); - if ( setting->type == NULL ) { - DBG ( "Invalid setting type \"%s\" in \"%s\"\n", - type_name, name ); - return -ENOTSUP; - } - } - - return 0; -} - -/** - * Parse and store value of named setting - * - * @v name Name of setting - * @v value Formatted setting data, or NULL - * @ret rc Return status code - */ -int storef_named_setting ( const char *name, const char *value ) { - struct settings *settings; - struct setting setting; - char tmp_name[ strlen ( name ) + 1 ]; - int rc; - - if ( ( rc = parse_setting_name ( name, autovivify_child_settings, - &settings, &setting, tmp_name )) != 0) - return rc; - return storef_setting ( settings, &setting, value ); -} - -/** - * Fetch and format value of named setting - * - * @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 fetchf_named_setting ( const char *name, char *buf, size_t len ) { - struct settings *settings; - struct setting setting; - char tmp_name[ strlen ( name ) + 1 ]; - int rc; - - if ( ( rc = parse_setting_name ( name, find_child_settings, - &settings, &setting, tmp_name )) != 0) - return rc; - return fetchf_setting ( settings, &setting, buf, len ); -} - -/****************************************************************************** - * - * Setting types - * - ****************************************************************************** - */ - -/** - * Parse and store value of string setting - * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @ret rc Return status code - */ -static int storef_string ( struct settings *settings, struct setting *setting, - const char *value ) { - return store_setting ( settings, setting, value, strlen ( value ) ); -} - -/** - * Fetch and format value of string setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v buf Buffer to contain formatted value - * @v len Length of buffer - * @ret len Length of formatted value, or negative error - */ -static int fetchf_string ( struct settings *settings, struct setting *setting, - char *buf, size_t len ) { - return fetch_string_setting ( settings, setting, buf, len ); -} - -/** A string setting type */ -struct setting_type setting_type_string __setting_type = { - .name = "string", - .storef = storef_string, - .fetchf = fetchf_string, -}; - -/** - * Parse and store value of URI-encoded string setting - * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @ret rc Return status code - */ -static int storef_uristring ( struct settings *settings, - struct setting *setting, - const char *value ) { - char buf[ strlen ( value ) + 1 ]; /* Decoding never expands string */ - size_t len; - - len = uri_decode ( value, buf, sizeof ( buf ) ); - return store_setting ( settings, setting, buf, len ); -} - -/** - * Fetch and format value of URI-encoded string setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v buf Buffer to contain formatted value - * @v len Length of buffer - * @ret len Length of formatted value, or negative error - */ -static int fetchf_uristring ( struct settings *settings, - struct setting *setting, - char *buf, size_t len ) { - ssize_t raw_len; - - /* We need to always retrieve the full raw string to know the - * length of the encoded string. - */ - raw_len = fetch_setting ( settings, setting, NULL, 0 ); - if ( raw_len < 0 ) - return raw_len; - - { - char raw_buf[ raw_len + 1 ]; - - fetch_string_setting ( settings, setting, raw_buf, - sizeof ( raw_buf ) ); - return uri_encode ( raw_buf, buf, len, URI_FRAGMENT ); - } -} - -/** A URI-encoded string setting type */ -struct setting_type setting_type_uristring __setting_type = { - .name = "uristring", - .storef = storef_uristring, - .fetchf = fetchf_uristring, -}; - -/** - * Parse and store value of IPv4 address setting - * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @ret rc Return status code - */ -static int storef_ipv4 ( struct settings *settings, struct setting *setting, - const char *value ) { - struct in_addr ipv4; - - if ( inet_aton ( value, &ipv4 ) == 0 ) - return -EINVAL; - return store_setting ( settings, setting, &ipv4, sizeof ( ipv4 ) ); -} - -/** - * Fetch and format value of IPv4 address setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v buf Buffer to contain formatted value - * @v len Length of buffer - * @ret len Length of formatted value, or negative error - */ -static int fetchf_ipv4 ( struct settings *settings, struct setting *setting, - char *buf, size_t len ) { - struct in_addr ipv4; - int raw_len; - - if ( ( raw_len = fetch_ipv4_setting ( settings, setting, &ipv4 ) ) < 0) - return raw_len; - return snprintf ( buf, len, "%s", inet_ntoa ( ipv4 ) ); -} - -/** An IPv4 address setting type */ -struct setting_type setting_type_ipv4 __setting_type = { - .name = "ipv4", - .storef = storef_ipv4, - .fetchf = fetchf_ipv4, -}; - -/** - * Parse and store value of integer setting - * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @v size Integer size, in bytes - * @ret rc Return status code - */ -static int storef_int ( struct settings *settings, struct setting *setting, - const char *value, unsigned int size ) { - union { - uint32_t num; - uint8_t bytes[4]; - } u; - char *endp; - - u.num = htonl ( strtoul ( value, &endp, 0 ) ); - if ( *endp ) - return -EINVAL; - return store_setting ( settings, setting, - &u.bytes[ sizeof ( u ) - size ], size ); -} - -/** - * Parse and store value of 8-bit integer setting - * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @v size Integer size, in bytes - * @ret rc Return status code - */ -static int storef_int8 ( struct settings *settings, struct setting *setting, - const char *value ) { - return storef_int ( settings, setting, value, 1 ); -} - -/** - * Parse and store value of 16-bit integer setting - * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @v size Integer size, in bytes - * @ret rc Return status code - */ -static int storef_int16 ( struct settings *settings, struct setting *setting, - const char *value ) { - return storef_int ( settings, setting, value, 2 ); -} - -/** - * Parse and store value of 32-bit integer setting - * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @v size Integer size, in bytes - * @ret rc Return status code - */ -static int storef_int32 ( struct settings *settings, struct setting *setting, - const char *value ) { - return storef_int ( settings, setting, value, 4 ); -} - -/** - * Fetch and format value of signed integer setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v buf Buffer to contain formatted value - * @v len Length of buffer - * @ret len Length of formatted value, or negative error - */ -static int fetchf_int ( struct settings *settings, struct setting *setting, - char *buf, size_t len ) { - long value; - int rc; - - if ( ( rc = fetch_int_setting ( settings, setting, &value ) ) < 0 ) - return rc; - return snprintf ( buf, len, "%ld", value ); -} - -/** - * Fetch and format value of unsigned integer setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v buf Buffer to contain formatted value - * @v len Length of buffer - * @ret len Length of formatted value, or negative error - */ -static int fetchf_uint ( struct settings *settings, struct setting *setting, - char *buf, size_t len ) { - unsigned long value; - int rc; - - if ( ( rc = fetch_uint_setting ( settings, setting, &value ) ) < 0 ) - return rc; - return snprintf ( buf, len, "%#lx", value ); -} - -/** A signed 8-bit integer setting type */ -struct setting_type setting_type_int8 __setting_type = { - .name = "int8", - .storef = storef_int8, - .fetchf = fetchf_int, -}; - -/** A signed 16-bit integer setting type */ -struct setting_type setting_type_int16 __setting_type = { - .name = "int16", - .storef = storef_int16, - .fetchf = fetchf_int, -}; - -/** A signed 32-bit integer setting type */ -struct setting_type setting_type_int32 __setting_type = { - .name = "int32", - .storef = storef_int32, - .fetchf = fetchf_int, -}; - -/** An unsigned 8-bit integer setting type */ -struct setting_type setting_type_uint8 __setting_type = { - .name = "uint8", - .storef = storef_int8, - .fetchf = fetchf_uint, -}; - -/** An unsigned 16-bit integer setting type */ -struct setting_type setting_type_uint16 __setting_type = { - .name = "uint16", - .storef = storef_int16, - .fetchf = fetchf_uint, -}; - -/** An unsigned 32-bit integer setting type */ -struct setting_type setting_type_uint32 __setting_type = { - .name = "uint32", - .storef = storef_int32, - .fetchf = fetchf_uint, -}; - -/** - * Parse and store value of hex string setting - * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @ret rc Return status code - */ -static int storef_hex ( struct settings *settings, struct setting *setting, - const char *value ) { - char *ptr = ( char * ) value; - uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */ - unsigned int len = 0; - - while ( 1 ) { - bytes[len++] = strtoul ( ptr, &ptr, 16 ); - switch ( *ptr ) { - case '\0' : - return store_setting ( settings, setting, bytes, len ); - case ':' : - ptr++; - break; - default : - return -EINVAL; - } - } -} - -/** - * Fetch and format value of hex string setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v buf Buffer to contain formatted value - * @v len Length of buffer - * @ret len Length of formatted value, or negative error - */ -static int fetchf_hex ( struct settings *settings, struct setting *setting, - char *buf, size_t len ) { - int raw_len; - int check_len; - int used = 0; - int i; - - raw_len = fetch_setting_len ( settings, setting ); - if ( raw_len < 0 ) - return raw_len; - - { - uint8_t raw[raw_len]; - - check_len = fetch_setting ( settings, setting, raw, - sizeof ( raw ) ); - if ( check_len < 0 ) - return check_len; - 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; - } -} - -/** A hex-string setting */ -struct setting_type setting_type_hex __setting_type = { - .name = "hex", - .storef = storef_hex, - .fetchf = fetchf_hex, -}; - -/** - * Parse and store value of UUID setting - * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @ret rc Return status code - */ -static int storef_uuid ( struct settings *settings __unused, - struct setting *setting __unused, - const char *value __unused ) { - return -ENOTSUP; -} - -/** - * Fetch and format value of UUID setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v buf Buffer to contain formatted value - * @v len Length of buffer - * @ret len Length of formatted value, or negative error - */ -static int fetchf_uuid ( struct settings *settings, struct setting *setting, - char *buf, size_t len ) { - union uuid uuid; - int raw_len; - - if ( ( raw_len = fetch_uuid_setting ( settings, setting, &uuid ) ) < 0) - return raw_len; - return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) ); -} - -/** UUID setting type */ -struct setting_type setting_type_uuid __setting_type = { - .name = "uuid", - .storef = storef_uuid, - .fetchf = fetchf_uuid, -}; - -/****************************************************************************** - * - * Settings - * - ****************************************************************************** - */ - -/** Hostname setting */ -struct setting hostname_setting __setting = { - .name = "hostname", - .description = "Host name", - .tag = DHCP_HOST_NAME, - .type = &setting_type_string, -}; - -/** Filename setting */ -struct setting filename_setting __setting = { - .name = "filename", - .description = "Boot filename", - .tag = DHCP_BOOTFILE_NAME, - .type = &setting_type_string, -}; - -/** Root path setting */ -struct setting root_path_setting __setting = { - .name = "root-path", - .description = "iSCSI root path", - .tag = DHCP_ROOT_PATH, - .type = &setting_type_string, -}; - -/** Username setting */ -struct setting username_setting __setting = { - .name = "username", - .description = "User name", - .tag = DHCP_EB_USERNAME, - .type = &setting_type_string, -}; - -/** Password setting */ -struct setting password_setting __setting = { - .name = "password", - .description = "Password", - .tag = DHCP_EB_PASSWORD, - .type = &setting_type_string, -}; - -/** Priority setting */ -struct setting priority_setting __setting = { - .name = "priority", - .description = "Priority of these settings", - .tag = DHCP_EB_PRIORITY, - .type = &setting_type_int8, -}; |