summaryrefslogtreecommitdiffstats
path: root/src/core/exec.c
diff options
context:
space:
mode:
authorMichael Brown2011-03-28 18:35:23 +0200
committerMichael Brown2011-03-28 18:35:23 +0200
commitb5f5f735c1aa1817e460760b0c2da25e04ef7124 (patch)
treedbf65489648c94a26dea7af1f2ce46c5fbe2748f /src/core/exec.c
parent[cmdline] Allow ";" as an unconditional command separator (diff)
downloadipxe-b5f5f735c1aa1817e460760b0c2da25e04ef7124.tar.gz
ipxe-b5f5f735c1aa1817e460760b0c2da25e04ef7124.tar.xz
ipxe-b5f5f735c1aa1817e460760b0c2da25e04ef7124.zip
[cmdline] Expand settings within each command-line token individually
Perform settings expansion after tokenisation, and only at the point of executing each command. This allows statements such as dhcp && echo ${net0/ip} to work correctly. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/core/exec.c')
-rw-r--r--src/core/exec.c114
1 files changed, 79 insertions, 35 deletions
diff --git a/src/core/exec.c b/src/core/exec.c
index 217ed039..8da28827 100644
--- a/src/core/exec.c
+++ b/src/core/exec.c
@@ -217,6 +217,45 @@ int shell_stopped ( int stop ) {
}
/**
+ * Expand settings within a token list
+ *
+ * @v argc Argument count
+ * @v tokens Token list
+ * @v argv Argument list to fill in
+ * @ret rc Return status code
+ */
+static int expand_tokens ( int argc, char **tokens, char **argv ) {
+ int i;
+
+ /* Expand each token in turn */
+ for ( i = 0 ; i < argc ; i++ ) {
+ argv[i] = expand_settings ( tokens[i] );
+ if ( ! argv[i] )
+ goto err_expand_settings;
+ }
+
+ return 0;
+
+ err_expand_settings:
+ assert ( argv[i] == NULL );
+ for ( ; i >= 0 ; i-- )
+ free ( argv[i] );
+ return -ENOMEM;
+}
+
+/**
+ * Free an expanded token list
+ *
+ * @v argv Argument list
+ */
+static void free_tokens ( char **argv ) {
+
+ /* Free each expanded argument */
+ while ( *argv )
+ free ( *(argv++) );
+}
+
+/**
* Execute command line
*
* @v command Command line
@@ -225,58 +264,63 @@ int shell_stopped ( int stop ) {
* Execute the named command and arguments.
*/
int system ( const char *command ) {
+ int count = split_command ( ( char * ) command, NULL );
+ char *all_tokens[ count + 1 ];
int ( * process_next ) ( int rc );
- char *expcmd;
- char **argv;
+ char *command_copy;
+ char **tokens;
int argc;
- int count;
int process;
int rc = 0;
- /* Perform variable expansion */
- expcmd = expand_settings ( command );
- if ( ! expcmd )
+ /* Create modifiable copy of command */
+ command_copy = strdup ( command );
+ if ( ! command_copy )
return -ENOMEM;
- /* Count tokens */
- count = split_command ( expcmd, NULL );
-
- /* Create token array */
- if ( count ) {
- char * tokens[count + 1];
-
- split_command ( expcmd, tokens );
- tokens[count] = NULL;
- process = 1;
+ /* Split command into tokens */
+ split_command ( command_copy, all_tokens );
+ all_tokens[count] = NULL;
- for ( argv = tokens ; ; argv += ( argc + 1 ) ) {
+ /* Process individual commands */
+ process = 1;
+ for ( tokens = all_tokens ; ; tokens += ( argc + 1 ) ) {
- /* Find command terminator */
- argc = command_terminator ( argv, &process_next );
+ /* Find command terminator */
+ argc = command_terminator ( tokens, &process_next );
- /* Execute command */
- if ( process ) {
- argv[argc] = NULL;
- rc = execv ( argv[0], argv );
- }
+ /* Expand tokens and execute command */
+ if ( process ) {
+ char *argv[ argc + 1 ];
- /* Stop processing, if applicable */
- if ( shell_stopped ( SHELL_STOP_COMMAND ) )
+ /* Expand tokens */
+ if ( ( rc = expand_tokens ( argc, tokens, argv ) ) != 0)
break;
+ argv[argc] = NULL;
- /* Stop processing if we have reached the end
- * of the command.
- */
- if ( ! process_next )
- break;
+ /* Execute command */
+ rc = execv ( argv[0], argv );
- /* Determine whether or not to process next command */
- process = process_next ( rc );
+ /* Free tokens */
+ free_tokens ( argv );
}
+
+ /* Stop processing, if applicable */
+ if ( shell_stopped ( SHELL_STOP_COMMAND ) )
+ break;
+
+ /* Stop processing if we have reached the end of the
+ * command.
+ */
+ if ( ! process_next )
+ break;
+
+ /* Determine whether or not to process next command */
+ process = process_next ( rc );
}
- /* Free expanded command */
- free ( expcmd );
+ /* Free modified copy of command */
+ free ( command_copy );
return rc;
}