[cmdline] Add setting expansion using ${...} syntax
authorMichael Brown <mcb30@etherboot.org>
Sun, 27 Jul 2008 00:08:20 +0000 (01:08 +0100)
committerMichael Brown <mcb30@etherboot.org>
Sun, 27 Jul 2008 00:08:20 +0000 (01:08 +0100)
Allow settings to be expanded in arbitrary commands, such as

  kernel http://10.0.0.1/boot.php?uuid=${uuid}

Also add the "echo" command, as being the easiest way to test this
features.

src/core/exec.c

index a1c073e..a9861b6 100644 (file)
@@ -26,6 +26,7 @@
 #include <assert.h>
 #include <gpxe/tables.h>
 #include <gpxe/command.h>
+#include <gpxe/settings.h>
 
 /** @file
  *
@@ -86,6 +87,76 @@ int execv ( const char *command, char * const argv[] ) {
        return -ENOEXEC;
 }
 
+/**
+ * Expand variables within command line
+ *
+ * @v command          Command line
+ * @ret expcmd         Expanded command line
+ *
+ * The expanded command line is allocated with malloc() and the caller
+ * must eventually free() it.
+ */
+static char * expand_command ( const char *command ) {
+       char *expcmd;
+       char *start;
+       char *end;
+       char *head;
+       char *name;
+       char *tail;
+       int setting_len;
+       int new_len;
+       char *tmp;
+
+       /* Obtain temporary modifiable copy of command line */
+       expcmd = strdup ( command );
+       if ( ! expcmd )
+               return NULL;
+
+       /* Expand while expansions remain */
+       while ( 1 ) {
+
+               head = expcmd;
+
+               /* Locate opener */
+               start = strstr ( expcmd, "${" );
+               if ( ! start )
+                       break;
+               *start = '\0';
+               name = ( start + 2 );
+
+               /* Locate closer */
+               end = strstr ( name, "}" );
+               if ( ! end )
+                       break;
+               *end = '\0';
+               tail = ( end + 1 );
+
+               /* Determine setting length */
+               setting_len = fetchf_named_setting ( name, NULL, 0 );
+               if ( setting_len < 0 )
+                       setting_len = 0; /* Treat error as empty setting */
+
+               /* Read setting into temporary buffer */
+               {
+                       char setting_buf[ setting_len + 1 ];
+
+                       setting_buf[0] = '\0';
+                       fetchf_named_setting ( name, setting_buf,
+                                              sizeof ( setting_buf ) );
+
+                       /* Construct expanded string and discard old string */
+                       tmp = expcmd;
+                       new_len = asprintf ( &expcmd, "%s%s%s",
+                                            head, setting_buf, tail );
+                       free ( tmp );
+                       if ( new_len < 0 )
+                               return NULL;
+               }
+       }
+
+       return expcmd;
+}
+
 /**
  * Split command line into argv array
  *
@@ -135,8 +206,8 @@ int system ( const char *command ) {
        int argc;
        int rc = 0;
 
-       /* Obtain temporary modifiable copy of command line */
-       args = strdup ( command );
+       /* Perform variable expansion */
+       args = expand_command ( command );
        if ( ! args )
                return -ENOMEM;
 
@@ -157,3 +228,26 @@ int system ( const char *command ) {
        free ( args );
        return rc;
 }
+
+/**
+ * The "echo" command
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @ret rc             Exit code
+ */
+static int echo_exec ( int argc, char **argv ) {
+       int i;
+
+       for ( i = 1 ; i < argc ; i++ ) {
+               printf ( "%s%s", ( ( i == 1 ) ? "" : " " ), argv[i] );
+       }
+       printf ( "\n" );
+       return 0;
+}
+
+/** "echo" command */
+struct command echo_command __command = {
+       .name = "echo",
+       .exec = echo_exec,
+};