]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[settings] Make "netX" settings block function as a symbolic link
authorMichael Brown <mcb30@ipxe.org>
Sat, 13 Jul 2013 13:06:20 +0000 (15:06 +0200)
committerMichael Brown <mcb30@ipxe.org>
Sat, 13 Jul 2013 13:11:45 +0000 (15:11 +0200)
Add a facility for settings blocks to act as symbolic links to other
settings blocks, and reimplement the "netX" virtual settings block
using this facility.

The primary advantage of this approach is that unscoped settings such
as ${mac} and ${filename} will now reflect the settings obtained from
the most recently opened network device: in most cases, this will mean
the settings obtained from the most recent DHCP attempt.  This should
improve conformance to the principle of least astonishment.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/core/settings.c
src/hci/tui/settings_ui.c
src/include/ipxe/settings.h
src/net/netdev_settings.c

index 927ad84590b88761fe77f1bbb056e0d2347916c8..80cd6a9f4b5ab3771db6294ae9e06d62f0de72e1 100644 (file)
@@ -271,6 +271,9 @@ struct settings * find_child_settings ( struct settings *parent,
                                        const char *name ) {
        struct settings *settings;
 
+       /* Find target parent settings block */
+       parent = settings_target ( parent );
+
        /* Treat empty name as meaning "this block" */
        if ( ! *name )
                return parent;
@@ -278,7 +281,7 @@ struct settings * find_child_settings ( struct settings *parent,
        /* Look for child with matching name */
        list_for_each_entry ( settings, &parent->children, siblings ) {
                if ( strcmp ( settings->name, name ) == 0 )
-                       return settings;
+                       return settings_target ( settings );
        }
 
        return NULL;
@@ -299,6 +302,9 @@ static struct settings * autovivify_child_settings ( struct settings *parent,
        } *new_child;
        struct settings *settings;
 
+       /* Find target parent settings block */
+       parent = settings_target ( parent );
+
        /* Return existing settings, if existent */
        if ( ( settings = find_child_settings ( parent, name ) ) != NULL )
                return settings;
@@ -330,6 +336,10 @@ const char * settings_name ( struct settings *settings ) {
        static char buf[16];
        char tmp[ sizeof ( buf ) ];
 
+       /* Find target settings block */
+       settings = settings_target ( settings );
+
+       /* Construct name */
        for ( buf[2] = buf[0] = 0 ; settings ; settings = settings->parent ) {
                memcpy ( tmp, buf, sizeof ( tmp ) );
                snprintf ( buf, sizeof ( buf ), ".%s%s", settings->name, tmp );
@@ -359,20 +369,11 @@ parse_settings_name ( const char *name,
 
        /* 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 );
-
+               settings = get_child ( settings, subname );
                if ( ! settings )
                        break;
        }
@@ -460,10 +461,11 @@ int register_settings ( struct settings *settings, struct settings *parent,
                        const char *name ) {
        struct settings *old_settings;
 
-       /* NULL parent => add to settings root */
+       /* Sanity check */
        assert ( settings != NULL );
-       if ( parent == NULL )
-               parent = &settings_root;
+
+       /* Find target parent settings block */
+       parent = settings_target ( parent );
 
        /* Apply settings block name */
        settings->name = name;
@@ -523,6 +525,26 @@ void unregister_settings ( struct settings *settings ) {
  ******************************************************************************
  */
 
+/**
+ * Redirect to target settings block
+ *
+ * @v settings         Settings block, or NULL
+ * @ret settings       Underlying settings block
+ */
+struct settings * settings_target ( struct settings *settings ) {
+
+       /* NULL settings implies the global settings root */
+       if ( ! settings )
+               settings = &settings_root;
+
+       /* Redirect to underlying settings block, if applicable */
+       if ( settings->op->redirect )
+               return settings->op->redirect ( settings );
+
+       /* Otherwise, return this settings block */
+       return settings;
+}
+
 /**
  * Check applicability of setting
  *
@@ -532,6 +554,10 @@ void unregister_settings ( struct settings *settings ) {
  */
 int setting_applies ( struct settings *settings, struct setting *setting ) {
 
+       /* Find target settings block */
+       settings = settings_target ( settings );
+
+       /* Check applicability of setting */
        return ( settings->op->applies ?
                 settings->op->applies ( settings, setting ) : 1 );
 }
@@ -549,9 +575,8 @@ 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;
+       /* Find target settings block */
+       settings = settings_target ( settings );
 
        /* Fail if tag does not apply to this settings block */
        if ( ! setting_applies ( settings, setting ) )
@@ -609,9 +634,8 @@ static int fetch_setting_and_origin ( struct settings *settings,
        if ( origin )
                *origin = NULL;
 
-       /* NULL settings implies starting at the global settings root */
-       if ( ! settings )
-               settings = &settings_root;
+       /* Find target settings block */
+       settings = settings_target ( settings );
 
        /* Sanity check */
        if ( ! settings->op->fetch )
@@ -971,6 +995,11 @@ int fetch_uuid_setting ( struct settings *settings, struct setting *setting,
  * @v settings         Settings block
  */
 void clear_settings ( struct settings *settings ) {
+
+       /* Find target settings block */
+       settings = settings_target ( settings );
+
+       /* Clear settings, if applicable */
        if ( settings->op->clear )
                settings->op->clear ( settings );
 }
@@ -1230,9 +1259,7 @@ int setting_name ( struct settings *settings, struct setting *setting,
                   char *buf, size_t len ) {
        const char *name;
 
-       if ( ! settings )
-               settings = &settings_root;
-
+       settings = settings_target ( settings );
        name = settings_name ( settings );
        return snprintf ( buf, len, "%s%s%s:%s", name, ( name[0] ? "/" : "" ),
                          setting->name, setting->type->name );
index 403d12453e32ac818519fd6e0c80398df15daa67..eb82ae54cf6f62618661bd9dba2b12bc2868e708 100644 (file)
@@ -441,7 +441,7 @@ static void reveal_setting_row ( struct setting_widget *widget,
 static void init_widget ( struct setting_widget *widget,
                          struct settings *settings ) {
 
-       widget->settings = settings;
+       widget->settings = settings_target ( settings );
        widget->num_rows = select_setting_row ( widget, 0 );
        widget->first_visible = SETTINGS_LIST_ROWS;
        draw_title_row ( widget );
index 8ee9516ecbcc90c4deb718c2bc24e4707dfd5cbc..6e75251c5b956ba46ca99a1d1f8e4b05fb36a792 100644 (file)
@@ -77,6 +77,12 @@ struct setting {
 
 /** Settings block operations */
 struct settings_operations {
+       /** Redirect to underlying settings block (if applicable)
+        *
+        * @v settings          Settings block
+        * @ret settings        Underlying settings block
+        */
+       struct settings * ( * redirect ) ( struct settings *settings );
        /** Check applicability of setting
         *
         * @v settings          Settings block
@@ -248,6 +254,7 @@ extern int register_settings ( struct settings *settings,
                               struct settings *parent, const char *name );
 extern void unregister_settings ( struct settings *settings );
 
+extern struct settings * settings_target ( struct settings *settings );
 extern int setting_applies ( struct settings *settings,
                             struct setting *setting );
 extern int store_setting ( struct settings *settings, struct setting *setting,
index 3ea7ace50419f40aa4d8c3b56232d8ad5e850b50..72152762cd46a0694f4d15c1ec6744ea7fad72fd 100644 (file)
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/settings.h>
 #include <ipxe/device.h>
 #include <ipxe/netdevice.h>
+#include <ipxe/init.h>
 
 /** @file
  *
@@ -295,3 +296,51 @@ struct settings_operations netdev_settings_operations = {
        .fetch = netdev_fetch,
        .clear = netdev_clear,
 };
+
+/**
+ * Redirect "netX" settings block
+ *
+ * @v settings         Settings block
+ * @ret settings       Underlying settings block
+ */
+static struct settings * netdev_redirect ( struct settings *settings ) {
+       struct net_device *netdev;
+
+       /* Redirect to most recently opened network device */
+       netdev = last_opened_netdev();
+       if ( netdev ) {
+               return netdev_settings ( netdev );
+       } else {
+               return settings;
+       }
+}
+
+/** "netX" settings operations */
+static struct settings_operations netdev_redirect_settings_operations = {
+       .redirect = netdev_redirect,
+};
+
+/** "netX" settings */
+static struct settings netdev_redirect_settings = {
+       .refcnt = NULL,
+       .siblings = LIST_HEAD_INIT ( netdev_redirect_settings.siblings ),
+       .children = LIST_HEAD_INIT ( netdev_redirect_settings.children ),
+       .op = &netdev_redirect_settings_operations,
+};
+
+/** Initialise "netX" settings */
+static void netdev_redirect_settings_init ( void ) {
+       int rc;
+
+       if ( ( rc = register_settings ( &netdev_redirect_settings, NULL,
+                                       "netX" ) ) != 0 ) {
+               DBG ( "Could not register netX settings: %s\n",
+                     strerror ( rc ) );
+               return;
+       }
+}
+
+/** "netX" settings initialiser */
+struct init_fn netdev_redirect_settings_init_fn __init_fn ( INIT_LATE ) = {
+       .initialise = netdev_redirect_settings_init,
+};