mirror of https://github.com/ipxe/ipxe.git
[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>pull/1/head
parent
1f4c5f90c3
commit
b5f5f735c1
116
src/core/exec.c
116
src/core/exec.c
|
@ -216,6 +216,45 @@ int shell_stopped ( int stop ) {
|
||||||
return stopped;
|
return stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Execute command line
|
||||||
*
|
*
|
||||||
|
@ -225,58 +264,63 @@ int shell_stopped ( int stop ) {
|
||||||
* Execute the named command and arguments.
|
* Execute the named command and arguments.
|
||||||
*/
|
*/
|
||||||
int system ( const char *command ) {
|
int system ( const char *command ) {
|
||||||
|
int count = split_command ( ( char * ) command, NULL );
|
||||||
|
char *all_tokens[ count + 1 ];
|
||||||
int ( * process_next ) ( int rc );
|
int ( * process_next ) ( int rc );
|
||||||
char *expcmd;
|
char *command_copy;
|
||||||
char **argv;
|
char **tokens;
|
||||||
int argc;
|
int argc;
|
||||||
int count;
|
|
||||||
int process;
|
int process;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
/* Perform variable expansion */
|
/* Create modifiable copy of command */
|
||||||
expcmd = expand_settings ( command );
|
command_copy = strdup ( command );
|
||||||
if ( ! expcmd )
|
if ( ! command_copy )
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Count tokens */
|
/* Split command into tokens */
|
||||||
count = split_command ( expcmd, NULL );
|
split_command ( command_copy, all_tokens );
|
||||||
|
all_tokens[count] = NULL;
|
||||||
|
|
||||||
/* Create token array */
|
/* Process individual commands */
|
||||||
if ( count ) {
|
process = 1;
|
||||||
char * tokens[count + 1];
|
for ( tokens = all_tokens ; ; tokens += ( argc + 1 ) ) {
|
||||||
|
|
||||||
split_command ( expcmd, tokens );
|
|
||||||
tokens[count] = NULL;
|
|
||||||
process = 1;
|
|
||||||
|
|
||||||
for ( argv = tokens ; ; argv += ( argc + 1 ) ) {
|
/* Find command terminator */
|
||||||
|
argc = command_terminator ( tokens, &process_next );
|
||||||
|
|
||||||
/* Find command terminator */
|
/* Expand tokens and execute command */
|
||||||
argc = command_terminator ( argv, &process_next );
|
if ( process ) {
|
||||||
|
char *argv[ argc + 1 ];
|
||||||
|
|
||||||
|
/* Expand tokens */
|
||||||
|
if ( ( rc = expand_tokens ( argc, tokens, argv ) ) != 0)
|
||||||
|
break;
|
||||||
|
argv[argc] = NULL;
|
||||||
|
|
||||||
/* Execute command */
|
/* Execute command */
|
||||||
if ( process ) {
|
rc = execv ( argv[0], argv );
|
||||||
argv[argc] = NULL;
|
|
||||||
rc = execv ( argv[0], argv );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop processing, if applicable */
|
/* Free tokens */
|
||||||
if ( shell_stopped ( SHELL_STOP_COMMAND ) )
|
free_tokens ( argv );
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 modified copy of command */
|
||||||
free ( expcmd );
|
free ( command_copy );
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue