summaryrefslogtreecommitdiffstats
path: root/src/core/exec.c
diff options
context:
space:
mode:
authorMichael Brown2010-11-29 15:19:59 +0100
committerMichael Brown2010-11-29 15:19:59 +0100
commit7bebe9579ee5ea1cfcfcdf25032dbab80ccc489f (patch)
tree1d9a7812b7b79c1ba5f71af8ce01823cb89763a0 /src/core/exec.c
parent[parseopt] Allow "0x"-prefixed hexadecimal values in integer-valued options (diff)
downloadipxe-7bebe9579ee5ea1cfcfcdf25032dbab80ccc489f.tar.gz
ipxe-7bebe9579ee5ea1cfcfcdf25032dbab80ccc489f.tar.xz
ipxe-7bebe9579ee5ea1cfcfcdf25032dbab80ccc489f.zip
[cmdline] Match user expectations for &&, ||, goto, and exit
The && and || operators should be left-associative, since that is how they are treated in most other languages (including C and Unix shell). For example, in the command: dhcp net0 && goto dhcp_ok || echo No DHCP on net0 if the "dhcp net0" fails then the "echo" should be executed. After an "exit" or a successful "goto", further commands on the same line should never be executed. For example: goto somewhere && echo This should never be printed exit 0 && echo This should never be printed exit 1 && echo This should never be printed An "exit" should cause the current shell or script to terminate and return the specified exit status to its caller. For example: chain test.ipxe && echo Success || echo Failure [in test.ipxe] #!ipxe exit 0 should echo "Success". Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/core/exec.c')
-rw-r--r--src/core/exec.c106
1 files changed, 65 insertions, 41 deletions
diff --git a/src/core/exec.c b/src/core/exec.c
index d96b8a76..bb3b343d 100644
--- a/src/core/exec.c
+++ b/src/core/exec.c
@@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/settings.h>
+#include <ipxe/shell.h>
/** @file
*
@@ -38,15 +39,15 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
-/** Shell exit flag */
-int shell_exit;
+/** Shell stop state */
+static int stop_state;
/**
* Execute command
*
* @v command Command name
* @v argv Argument list
- * @ret rc Command exit status
+ * @ret rc Return status code
*
* Execute the named command. Unlike a traditional POSIX execv(),
* this function returns the exit status of the command.
@@ -196,32 +197,22 @@ static int split_command ( char *command, char **tokens ) {
}
/**
- * 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
+ * Process next command only if previous command succeeded
*
* @v rc Status of previous command
- * @ret terminate Terminate command
+ * @ret process Process next command
*/
-static int terminate_on_success ( int rc ) {
+static int process_on_success ( int rc ) {
return ( rc == 0 );
}
/**
- * Terminate command only if previous command failed
+ * Process next command only if previous command failed
*
* @v rc Status of previous command
- * @ret terminate Terminate command
+ * @ret process Process next command
*/
-static int terminate_on_failure ( int rc ) {
+static int process_on_failure ( int rc ) {
return ( rc != 0 );
}
@@ -229,54 +220,79 @@ static int terminate_on_failure ( int rc ) {
* Find command terminator
*
* @v tokens Token list
- * @ret terminator Terminator type
+ * @ret process_next "Should next command be processed?" function
* @ret argc Argument count
*/
static int command_terminator ( char **tokens,
- int ( **terminator ) ( int rc ) ) {
+ int ( **process_next ) ( 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;
+ break;
} else if ( strcmp ( tokens[i], "||" ) == 0 ) {
/* Short-circuit logical OR */
- *terminator = terminate_on_success;
+ *process_next = process_on_failure;
return i;
} else if ( strcmp ( tokens[i], "&&" ) == 0 ) {
/* Short-circuit logical AND */
- *terminator = terminate_on_failure;
+ *process_next = process_on_success;
return i;
}
}
/* End of token list */
- *terminator = terminate_always;
+ *process_next = NULL;
return i;
}
/**
+ * Set shell stop state
+ *
+ * @v stop Shell stop state
+ */
+void shell_stop ( int stop ) {
+ stop_state = stop;
+}
+
+/**
+ * Test and consume shell stop state
+ *
+ * @v stop Shell stop state to consume
+ * @v stopped Shell had been stopped
+ */
+int shell_stopped ( int stop ) {
+ int stopped;
+
+ /* Test to see if we need to stop */
+ stopped = ( stop_state >= stop );
+
+ /* Consume stop state */
+ if ( stop_state <= stop )
+ stop_state = 0;
+
+ return stopped;
+}
+
+/**
* Execute command line
*
* @v command Command line
- * @ret rc Command exit status
+ * @ret rc Return status code
*
* Execute the named command and arguments.
*/
int system ( const char *command ) {
- int ( * terminator ) ( int rc );
+ int ( * process_next ) ( int rc );
char *expcmd;
char **argv;
int argc;
int count;
+ int process;
int rc = 0;
- /* Reset exit flag */
- shell_exit = 0;
-
/* Perform variable expansion */
expcmd = expand_command ( command );
if ( ! expcmd )
@@ -291,23 +307,31 @@ int system ( const char *command ) {
split_command ( expcmd, tokens );
tokens[count] = NULL;
+ process = 1;
for ( argv = tokens ; ; argv += ( argc + 1 ) ) {
/* Find command terminator */
- argc = command_terminator ( argv, &terminator );
+ argc = command_terminator ( argv, &process_next );
/* Execute command */
- argv[argc] = NULL;
- rc = execv ( argv[0], argv );
+ if ( process ) {
+ argv[argc] = NULL;
+ rc = execv ( argv[0], argv );
+ }
- /* Check exit flag */
- if ( shell_exit )
+ /* Stop processing, if applicable */
+ if ( shell_stopped ( SHELL_STOP_COMMAND ) )
break;
- /* Handle terminator */
- if ( terminator ( rc ) )
+ /* 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 );
}
}
@@ -322,7 +346,7 @@ int system ( const char *command ) {
*
* @v argc Argument count
* @v argv Argument list
- * @ret rc Exit code
+ * @ret rc Return status code
*/
static int echo_exec ( int argc, char **argv ) {
int i;
@@ -373,8 +397,8 @@ static int exit_exec ( int argc, char **argv ) {
return rc;
}
- /* Set exit flag */
- shell_exit = 1;
+ /* Stop shell processing */
+ shell_stop ( SHELL_STOP_COMMAND_SEQUENCE );
return exit_code;
}