david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[cmdline] Add trivial logical operators to iPXE command lines

Make the "||" and "&&" operators available within iPXE commands.  For
example:

   dhcp net0 || set net0/ip 192.168.0.2

would attempt to acquire an IP address via DHCP, falling back to a
static address if DHCP fails.

As a side-effect, comments may now be appended to any line.  For
example:

  dhcp net0 || set net0/ip 192.168.0.2   # Try DHCP first, then static

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2010-11-22 01:47:07 +00:00
parent b91116e072
commit 9ba988809d
1 changed files with 115 additions and 36 deletions

View File

@ -58,12 +58,12 @@ int execv ( const char *command, char * const argv[] ) {
/* Count number of arguments */ /* Count number of arguments */
for ( argc = 0 ; argv[argc] ; argc++ ) {} for ( argc = 0 ; argv[argc] ; argc++ ) {}
/* An empty command is deemed to do nothing, successfully */
if ( command == NULL )
return 0;
/* Sanity checks */ /* Sanity checks */
if ( ! command ) { if ( argc == 0 ) {
DBG ( "No command\n" );
return -EINVAL;
}
if ( ! argc ) {
DBG ( "%s: empty argument list\n", command ); DBG ( "%s: empty argument list\n", command );
return -EINVAL; return -EINVAL;
} }
@ -156,39 +156,102 @@ static char * expand_command ( const char *command ) {
} }
/** /**
* Split command line into argv array * Split command line into tokens
* *
* @v args Command line * @v command Command line
* @v argv Argument array to populate, or NULL * @v tokens Token list to populate, or NULL
* @ret argc Argument count * @ret count Number of tokens
* *
* Splits the command line into whitespace-delimited arguments. If @c * Splits the command line into whitespace-delimited tokens. If @c
* argv is non-NULL, any whitespace in the command line will be * tokens is non-NULL, any whitespace in the command line will be
* replaced with NULs. * replaced with NULs.
*/ */
static int split_args ( char *args, char * argv[] ) { static int split_command ( char *command, char **tokens ) {
int argc = 0; int count = 0;
while ( 1 ) { while ( 1 ) {
/* Skip over any whitespace / convert to NUL */ /* Skip over any whitespace / convert to NUL */
while ( isspace ( *args ) ) { while ( isspace ( *command ) ) {
if ( argv ) if ( tokens )
*args = '\0'; *command = '\0';
args++; command++;
} }
/* Check for end of line */ /* Check for end of line */
if ( ! *args ) if ( ! *command )
break; break;
/* We have found the start of the next argument */ /* We have found the start of the next argument */
if ( argv ) if ( tokens )
argv[argc] = args; tokens[count] = command;
argc++; count++;
/* Skip to start of next whitespace, if any */ /* Skip to start of next whitespace, if any */
while ( *args && ! isspace ( *args ) ) { while ( *command && ! isspace ( *command ) ) {
args++; command++;
} }
} }
return argc; return count;
}
/**
* Terminate command unconditionally
*
* @v rc Status of previous command
* @ret terminate Terminate command
*/
static int terminate_always ( int rc __unused ) {
return 1;
}
/**
* Terminate command only if previous command succeeded
*
* @v rc Status of previous command
* @ret terminate Terminate command
*/
static int terminate_on_success ( int rc ) {
return ( rc == 0 );
}
/**
* Terminate command only if previous command failed
*
* @v rc Status of previous command
* @ret terminate Terminate command
*/
static int terminate_on_failure ( int rc ) {
return ( rc != 0 );
}
/**
* Find command terminator
*
* @v tokens Token list
* @ret terminator Terminator type
* @ret argc Argument count
*/
static int command_terminator ( char **tokens,
int ( **terminator ) ( int rc ) ) {
unsigned int i;
/* Find first terminating token */
for ( i = 0 ; tokens[i] ; i++ ) {
if ( tokens[i][0] == '#' ) {
/* Start of a comment */
*terminator = terminate_always;
return i;
} else if ( strcmp ( tokens[i], "||" ) == 0 ) {
/* Short-circuit logical OR */
*terminator = terminate_on_success;
return i;
} else if ( strcmp ( tokens[i], "&&" ) == 0 ) {
/* Short-circuit logical AND */
*terminator = terminate_on_failure;
return i;
}
}
/* End of token list */
*terminator = terminate_always;
return i;
} }
/** /**
@ -200,30 +263,46 @@ static int split_args ( char *args, char * argv[] ) {
* Execute the named command and arguments. * Execute the named command and arguments.
*/ */
int system ( const char *command ) { int system ( const char *command ) {
char *args; int ( * terminator ) ( int rc );
char *expcmd;
char **argv;
int argc; int argc;
int count;
int rc = 0; int rc = 0;
/* Perform variable expansion */ /* Perform variable expansion */
args = expand_command ( command ); expcmd = expand_command ( command );
if ( ! args ) if ( ! expcmd )
return -ENOMEM; return -ENOMEM;
/* Count arguments */ /* Count tokens */
argc = split_args ( args, NULL ); count = split_command ( expcmd, NULL );
/* Create argv array and execute command */ /* Create token array */
if ( argc ) { if ( count ) {
char * argv[argc + 1]; char * tokens[count + 1];
split_args ( args, argv ); split_command ( expcmd, tokens );
tokens[count] = NULL;
for ( argv = tokens ; ; argv += ( argc + 1 ) ) {
/* Find command terminator */
argc = command_terminator ( argv, &terminator );
/* Execute command */
argv[argc] = NULL; argv[argc] = NULL;
if ( argv[0][0] != '#' )
rc = execv ( argv[0], argv ); rc = execv ( argv[0], argv );
/* Handle terminator */
if ( terminator ( rc ) )
break;
}
} }
free ( args ); /* Free expanded command */
free ( expcmd );
return rc; return rc;
} }