[Settings] Start revamping the configuration settings API.
authorMichael Brown <mcb30@etherboot.org>
Thu, 20 Mar 2008 04:06:07 +0000 (04:06 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 20 Mar 2008 04:06:07 +0000 (04:06 +0000)
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.

src/core/settings.c
src/hci/commands/config_cmd.c
src/hci/commands/nvo_cmd.c
src/hci/tui/settings_ui.c
src/include/gpxe/settings.h
src/include/gpxe/settings_ui.h

index 1cf711d..a5c7f81 100644 (file)
@@ -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
  *
  */
 
-/** 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,
-       }
 };
index 368a6ca..49cc41e 100644 (file)
@@ -4,28 +4,27 @@
 #include <gpxe/settings.h>
 #include <gpxe/settings_ui.h>
 
-
-#include <gpxe/nvo.h>
-extern struct nvo_block *ugly_nvo_hack;
-
-
 static int config_exec ( int argc, char **argv ) {
-       struct config_context dummy_context;
+       struct settings *settings;
        int rc;
 
-       if ( argc != 1 ) {
-               printf ( "Usage: %s\n"
+       if ( argc > 2 ) {
+               printf ( "Usage: %s [scope]\n"
                         "Opens the option configuration console\n", argv[0] );
                return 1;
        }
 
-       if ( ! ugly_nvo_hack ) {
-               printf ( "No non-volatile option storage available\n" );
-               return 1;
+       if ( argc == 2 ) {
+               settings = find_settings ( argv[1] );
+               if ( ! settings ) {
+                       printf ( "No such scope \"%s\"\n", argv[1] );
+                       return 1;
+               }
+       } else {
+               settings = &interactive_settings;
        }
 
-       dummy_context.options = ugly_nvo_hack->options;
-       if ( ( rc = settings_ui ( &dummy_context ) ) != 0 ) {
+       if ( ( rc = settings_ui ( settings ) ) != 0 ) {
                printf ( "Could not save settings: %s\n",
                         strerror ( rc ) );
                return 1;
index 4c453c7..255e979 100644 (file)
@@ -4,33 +4,21 @@
 #include <string.h>
 #include <errno.h>
 #include <getopt.h>
-#include <gpxe/nvo.h>
-#include <gpxe/dhcp.h>
 #include <gpxe/settings.h>
 #include <gpxe/command.h>
 
-extern struct nvo_block *ugly_nvo_hack;
-
 static int show_exec ( int argc, char **argv ) {
-       struct config_context dummy_context;
        char buf[256];
        int rc;
 
-       if ( ! ugly_nvo_hack ) {
-               printf ( "No non-volatile option storage available\n" );
-               return 1;
-       }
-
        if ( argc != 2 ) {
                printf ( "Syntax: %s <identifier>\n", argv[0] );
                return 1;
        }
 
-       dummy_context.options = ugly_nvo_hack->options;
-       if ( ( rc = show_named_setting ( &dummy_context, argv[1], buf,
-                                        sizeof ( buf ) ) ) < 0 ) {
+       if ( ( rc = get_named_setting ( argv[1], buf, sizeof ( buf ) ) ) < 0 ){
                printf ( "Could not find \"%s\": %s\n",
-                        argv[1], strerror ( -rc ) );
+                        argv[1], strerror ( rc ) );
                return 1;
        }
 
@@ -39,30 +27,16 @@ static int show_exec ( int argc, char **argv ) {
 }
 
 static int set_exec ( int argc, char **argv ) {
-       struct config_context dummy_context;
        int rc;
 
-       if ( ! ugly_nvo_hack ) {
-               printf ( "No non-volatile option storage available\n" );
-               return 1;
-       }
-
        if ( argc != 3 ) {
-               printf ( "Syntax: %s <identifier> <value>\n",
-                        argv[0] );
+               printf ( "Syntax: %s <identifier> <value>\n", argv[0] );
                return 1;
        }
 
-       dummy_context.options = ugly_nvo_hack->options;
-       if ( ( rc = set_named_setting ( &dummy_context, argv[1],
-                                       argv[2] ) ) != 0 ) {
+       if ( ( rc = set_named_setting ( argv[1], argv[2] ) ) != 0 ) {
                printf ( "Could not set \"%s\"=\"%s\": %s\n",
-                        argv[1], argv[2], strerror ( -rc ) );
-               return 1;
-       }
-       
-       if ( nvo_save ( ugly_nvo_hack ) != 0 ) {
-               printf ( "Could not save options to non-volatile storage\n" );
+                        argv[1], argv[2], strerror ( rc ) );
                return 1;
        }
 
@@ -70,24 +44,16 @@ static int set_exec ( int argc, char **argv ) {
 }
 
 static int clear_exec ( int argc, char **argv ) {
-       struct config_context dummy_context;
        int rc;
 
-       if ( ! ugly_nvo_hack ) {
-               printf ( "No non-volatile option storage available\n" );
-               return 1;
-       }
-
        if ( argc != 2 ) {
-               printf ( "Syntax: %s <identifier>\n",
-                        argv[0] );
+               printf ( "Syntax: %s <identifier>\n", argv[0] );
                return 1;
        }
 
-       dummy_context.options = ugly_nvo_hack->options;
-       if ( ( rc = clear_named_setting ( &dummy_context, argv[1] ) ) != 0 ) {
+       if ( ( rc = delete_named_setting ( argv[1] ) ) != 0 ) {
                printf ( "Could not clear \"%s\": %s\n",
-                        argv[1], strerror ( -rc ) );
+                        argv[1], strerror ( rc ) );
                return 1;
        }
        
index c6261c7..a20dd44 100644 (file)
@@ -33,9 +33,6 @@
  *
  */
 
-#include <gpxe/nvo.h>
-extern struct nvo_block *ugly_nvo_hack;
-
 /* Colour pairs */
 #define CPAIR_NORMAL   1
 #define CPAIR_SELECT   2
@@ -64,10 +61,10 @@ struct setting_row {
 
 /** A setting widget */
 struct setting_widget {
-       /** Configuration context */
-       struct config_context *context;
+       /** Settings block */
+       struct settings *settings;
        /** Configuration setting */
-       struct config_setting *setting;
+       struct named_setting *setting;
        /** Screen row */
        unsigned int row;
        /** Screen column */
@@ -81,32 +78,32 @@ struct setting_widget {
 };
 
 /** 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 );
-#define NUM_SETTINGS ( ( unsigned ) ( config_settings_end - config_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 );
+#define NUM_SETTINGS ( ( unsigned ) ( named_settings_end - named_settings ) )
 
 static void load_setting ( struct setting_widget *widget ) __nonnull;
 static int save_setting ( struct setting_widget *widget ) __nonnull;
 static void init_setting ( struct setting_widget *widget,
-                           struct config_context *context,
-                           struct config_setting *setting,
+                           struct settings *settings,
+                           struct named_setting *setting,
                            unsigned int row, unsigned int col ) __nonnull;
 static void draw_setting ( struct setting_widget *widget ) __nonnull;
 static int edit_setting ( struct setting_widget *widget, int key ) __nonnull;
 static void init_setting_index ( struct setting_widget *widget,
-                                 struct config_context *context,
+                                 struct settings *settings,
                                  unsigned int index ) __nonnull;
 static void vmsg ( unsigned int row, const char *fmt, va_list args ) __nonnull;
 static void msg ( unsigned int row, const char *fmt, ... ) __nonnull;
 static void valert ( const char *fmt, va_list args ) __nonnull;
 static void alert ( const char *fmt, ... ) __nonnull;
-static void draw_info_row ( struct config_setting *setting ) __nonnull;
-static int main_loop ( struct config_context *context ) __nonnull;
+static void draw_info_row ( struct named_setting *setting ) __nonnull;
+static int main_loop ( struct settings *settings ) __nonnull;
 
 /**
- * Load setting widget value from configuration context
+ * Load setting widget value from configuration settings
  *
  * @v widget           Setting widget
  *
@@ -117,8 +114,9 @@ static void load_setting ( struct setting_widget *widget ) {
        widget->editing = 0;
 
        /* Read current setting value */
-       if ( show_setting ( widget->context, widget->setting,
-                           widget->value, sizeof ( widget->value ) ) < 0 ) {
+       if ( get_typed_setting ( widget->settings, widget->setting->tag,
+                                widget->setting->type, widget->value,
+                                sizeof ( widget->value ) ) < 0 ) {
                widget->value[0] = '\0';
        }       
 
@@ -130,31 +128,32 @@ static void load_setting ( struct setting_widget *widget ) {
 }
 
 /**
- * Save setting widget value back to configuration context
+ * Save setting widget value back to configuration settings
  *
  * @v widget           Setting widget
  */
 static int save_setting ( struct setting_widget *widget ) {
-       return set_setting ( widget->context, widget->setting, widget->value );
+       return set_typed_setting ( widget->settings, widget->setting->tag,
+                                  widget->setting->type, widget->value );
 }
 
 /**
  * Initialise setting widget
  *
  * @v widget           Setting widget
- * @v context          Configuration context
+ * @v settings         Settings block
  * @v setting          Configuration setting
  * @v row              Screen row
  * @v col              Screen column
  */
 static void init_setting ( struct setting_widget *widget,
-                          struct config_context *context,
-                          struct config_setting *setting,
+                          struct settings *settings,
+                          struct named_setting *setting,
                           unsigned int row, unsigned int col ) {
 
        /* Initialise widget structure */
        memset ( widget, 0, sizeof ( *widget ) );
-       widget->context = context;
+       widget->settings = settings;
        widget->setting = setting;
        widget->row = row;
        widget->col = col;
@@ -219,13 +218,13 @@ static int edit_setting ( struct setting_widget *widget, int key ) {
  * Initialise setting widget by index
  *
  * @v widget           Setting widget
- * @v context          Configuration context
+ * @v settings         Settings block
  * @v index            Index of setting with settings list
  */
 static void init_setting_index ( struct setting_widget *widget,
-                                struct config_context *context,
+                                struct settings *settings,
                                 unsigned int index ) {
-       init_setting ( widget, context, &config_settings[index],
+       init_setting ( widget, settings, &named_settings[index],
                       ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
 }
 
@@ -312,11 +311,10 @@ static void draw_title_row ( void ) {
  *
  * @v setting          Current configuration setting
  */
-static void draw_info_row ( struct config_setting *setting ) {
+static void draw_info_row ( struct named_setting *setting ) {
        clearmsg ( INFO_ROW );
        attron ( A_BOLD );
-       msg ( INFO_ROW, "%s (%s) - %s", setting->name,
-             setting->type->description, setting->description );
+       msg ( INFO_ROW, "%s - %s", setting->name, setting->description );
        attroff ( A_BOLD );
 }
 
@@ -333,11 +331,11 @@ static void draw_instruction_row ( int editing ) {
                      "Ctrl-C - discard changes" );
        } else {
                msg ( INSTRUCTION_ROW,
-                     "Ctrl-S - save configuration" );
+                     "Ctrl-X - exit configuration utility" );
        }
 }
 
-static int main_loop ( struct config_context *context ) {
+static int main_loop ( struct settings *settings ) {
        struct setting_widget widget;
        unsigned int current = 0;
        unsigned int next;
@@ -349,7 +347,7 @@ static int main_loop ( struct config_context *context ) {
        draw_title_row();
        color_set ( CPAIR_NORMAL, NULL );
        for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
-               init_setting_index ( &widget, context, i );
+               init_setting_index ( &widget, settings, i );
                draw_setting ( &widget );
        }
 
@@ -394,19 +392,15 @@ static int main_loop ( struct config_context *context ) {
                                if ( next > 0 )
                                        next--;
                                break;
-                       case CTRL_S:
-                               if ( ( rc = nvo_save ( ugly_nvo_hack ) ) != 0){
-                                       alert ( " Could not save options: %s ",
-                                               strerror ( rc ) );
-                               }
-                               return rc;
+                       case CTRL_X:
+                               return 0;
                        default:
                                edit_setting ( &widget, key );
                                break;
                        }       
                        if ( next != current ) {
                                draw_setting ( &widget );
-                               init_setting_index ( &widget, context, next );
+                               init_setting_index ( &widget, settings, next );
                                current = next;
                        }
                }
@@ -414,7 +408,7 @@ static int main_loop ( struct config_context *context ) {
        
 }
 
-int settings_ui ( struct config_context *context ) {
+int settings_ui ( struct settings *settings ) {
        int rc;
 
        initscr();
@@ -426,7 +420,7 @@ int settings_ui ( struct config_context *context ) {
        color_set ( CPAIR_NORMAL, NULL );
        erase();
        
-       rc = main_loop ( context );
+       rc = main_loop ( settings );
 
        endwin();
 
index 1b9c059..7198399 100644 (file)
@@ -8,73 +8,96 @@
  */
 
 #include <stdint.h>
-#include <gpxe/dhcp.h>
 #include <gpxe/tables.h>
+#include <gpxe/list.h>
+#include <gpxe/refcnt.h>
 
-struct config_setting;
+struct settings;
+struct in_addr;
 
-/**
- * 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
+/** Settings block operations */
+struct settings_operations {
+       /** Set value of setting
+        *
+        * @v settings          Settings block
+        * @v tag               Setting tag number
+        * @v data              Setting data, or NULL to clear setting
+        * @v len               Length of setting data
+        * @ret rc              Return status code
+        */
+       int ( * set ) ( struct settings *settings, unsigned int tag,
+                       const void *data, size_t len );
+       /** Get value of setting
+        *
+        * @v settings          Settings block
+        * @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
         *
-        * If NULL, all registered DHCP options blocks will be used.
+        * The actual length of the setting will be returned even if
+        * the buffer was too small.
         */
-       struct dhcp_option_block *options;
+       int ( * get ) ( struct settings *settings, unsigned int tag,
+                       void *data, size_t len );
+};
+
+/** A settings block */
+struct settings {
+       /** Reference counter */
+       struct refcnt *refcnt;
+       /** Name */
+       char name[16];
+       /** List of all settings */
+       struct list_head list;
+       /** Settings block operations */
+       struct settings_operations *op;
 };
 
 /**
- * A configuration setting type
+ * A setting type
  *
- * This represents a type of configuration setting (e.g. string, IPv4
- * address, etc.).
+ * This represents a type of setting (e.g. string, IPv4 address,
+ * etc.).
  */
-struct config_setting_type {
+struct setting_type {
        /** Name
         *
         * This is the name exposed to the user (e.g. "string").
         */
        const char *name;
-       /** Description */
-       const char *description;
-       /** Show value of setting
+       /** Parse and set value of setting
         *
-        * @v context           Configuration context
-        * @v setting           Configuration setting
-        * @v buf               Buffer to contain value
+        * @v settings          Settings block
+        * @v tag               Setting tag number
+        * @v value             Formatted setting data
+        * @ret rc              Return status code
+        */
+       int ( * setf ) ( struct settings *settings, unsigned int tag,
+                        const char *value );
+       /** Get and format value of 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
         */
-       int ( * show ) ( struct config_context *context,
-                        struct config_setting *setting,
+       int ( * getf ) ( struct settings *settings, unsigned int tag,
                         char *buf, size_t len );
-       /** 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 ( struct config_setting_type, config_setting_types, 01 )
+#define        __setting_type \
+       __table ( struct setting_type, setting_types, 01 )
 
 /**
- * A configuration setting
+ * A named setting
  *
- * This represents a single configuration setting (e.g. "hostname").
+ * This represents a single setting (e.g. "hostname"), encapsulating
+ * the information about the setting's tag number and type.
  */
-struct config_setting {
+struct named_setting {
        /** Name
         *
         * This is the human-readable name for the setting.  Where
@@ -84,71 +107,90 @@ struct config_setting {
        const char *name;
        /** Description */
        const char *description;
-       /** DHCP option tag
-        *
-        * This is the DHCP tag used to identify the option in DHCP
-        * packets and stored option blocks.
-        */
+       /** Setting tag number */
        unsigned int tag;
-       /** Configuration setting type
+       /** Setting type
         *
         * This identifies the type of setting (e.g. string, IPv4
         * address, etc.).
         */
-       struct config_setting_type *type;
+       struct setting_type *type;
 };
 
 /** Declare a configuration setting */
-#define        __config_setting __table ( struct config_setting, config_settings, 01 )
+#define        __named_setting __table ( struct named_setting, named_settings, 01 )
+
+extern struct settings interactive_settings;
+
+extern int get_setting ( struct settings *settings, unsigned int tag,
+                        void *data, size_t len );
+extern int get_setting_len ( struct settings *settings, unsigned int tag );
+extern int get_string_setting ( struct settings *settings, unsigned int tag,
+                               char *data, size_t len );
+extern int get_ipv4_setting ( struct settings *settings, unsigned int tag,
+                             struct in_addr *inp );
+extern int get_int_setting ( struct settings *settings, unsigned int tag,
+                            long *value );
+extern int get_uint_setting ( struct settings *settings, unsigned int tag,
+                             unsigned long *value );
+extern struct settings * find_settings ( const char *name );
+extern int set_typed_setting ( struct settings *settings,
+                              unsigned int tag, struct setting_type *type,
+                              const char *value );
+extern int set_named_setting ( const char *name, const char *value );
+extern int get_named_setting ( const char *name, char *buf, size_t len );
 
 /**
- * Show value of setting
+ * Set value of 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
+ * @v settings         Settings block
+ * @v tag              Setting tag number
+ * @v data             Setting data, or NULL to clear setting
+ * @v len              Length of setting data
+ * @ret rc             Return status code
  */
-static inline int show_setting ( struct config_context *context,
-                                struct config_setting *setting,
-                                char *buf, size_t len ) {
-       return setting->type->show ( context, setting, buf, len );
+static inline int set_setting ( struct settings *settings, unsigned int tag,
+                               const void *data, size_t len ) {
+       return settings->op->set ( settings, tag, data, len );
 }
 
-extern int set_setting ( struct config_context *context,
-                        struct config_setting *setting,
-                        const char *value );
-
 /**
- * Clear setting
+ * Delete setting
  *
- * @v context          Configuration context
- * @v setting          Configuration setting
+ * @v settings         Settings block
+ * @v tag              Setting tag number
  * @ret rc             Return status code
  */
-static inline int clear_setting ( struct config_context *context,
-                                 struct config_setting *setting ) {
-       delete_dhcp_option ( context->options, setting->tag );
-       return 0;
+static inline int delete_setting ( struct settings *settings,
+                                  unsigned int tag ) {
+       return set_setting ( settings, tag, NULL, 0 );
 }
 
-/* Function prototypes */
-extern int show_named_setting ( struct config_context *context,
-                               const char *name, char *buf, size_t len );
-extern int set_named_setting ( struct config_context *context,
-                              const char *name, const char *value );
+/**
+ * Get and format value of setting
+ *
+ * @v settings         Settings block, or NULL to search all blocks
+ * @v tag              Setting tag number
+ * @v type             Settings type
+ * @v buf              Buffer to contain formatted value
+ * @v len              Length of buffer
+ * @ret len            Length of formatted value, or negative error
+ */
+static inline int get_typed_setting ( struct settings *settings,
+                                     unsigned int tag,
+                                     struct setting_type *type,
+                                     char *buf, size_t len ) {
+       return type->getf ( settings, tag, buf, len );
+}
 
 /**
- * Clear named setting
+ * Delete named setting
  *
- * @v context          Configuration context
- * @v name             Configuration setting name
+ * @v name             Name of setting
  * @ret rc             Return status code
  */
-static inline int clear_named_setting ( struct config_context *context,
-                                       const char *name ) {
-       return set_named_setting ( context, name, NULL );
+static inline int delete_named_setting ( const char *name ) {
+       return set_named_setting ( name, NULL );
 }
 
 #endif /* _GPXE_SETTINGS_H */
index 70ee8cb..48548fd 100644 (file)
@@ -7,8 +7,8 @@
  *
  */
 
-struct config_context;
+struct settings;
 
-extern int settings_ui ( struct config_context *context ) __nonnull;
+extern int settings_ui ( struct settings *settings ) __nonnull;
 
 #endif /* _GPXE_SETTINGS_UI_H */