Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[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>
  • Loading branch information
mcb30 committed Mar 28, 2011
1 parent 1f4c5f9 commit b5f5f73
Showing 1 changed file with 79 additions and 35 deletions.
114 changes: 79 additions & 35 deletions src/core/exec.c
Expand Up @@ -216,6 +216,45 @@ int shell_stopped ( int stop ) {
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
*
Expand All @@ -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;
}
Expand Down

0 comments on commit b5f5f73

Please sign in to comment.