diff --git a/doc/openocd.texi b/doc/openocd.texi index 4bec637f3..e418e0500 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6486,8 +6486,10 @@ Useful in connection with script files (@command{script} command and @command{target_name} configuration). @end deffn -@deffn Command shutdown -Close the OpenOCD daemon, disconnecting all clients (GDB, telnet, other). +@deffn Command shutdown [@option{error}] +Close the OpenOCD daemon, disconnecting all clients (GDB, telnet, +other). If option @option{error} is used, OpenOCD will return a +non-zero exit code to the parent process. @end deffn @anchor{debuglevel} diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl index 7a96a3e3b..fbb8d8ee4 100644 --- a/src/flash/startup.tcl +++ b/src/flash/startup.tcl @@ -8,8 +8,8 @@ proc program_error {description exit} { if {$exit == 1} { - echo $description - shutdown + echo $description + shutdown error } error $description diff --git a/src/helper/command.c b/src/helper/command.c index 9d19cff4f..a0aa9e857 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -121,7 +121,7 @@ static int command_retval_set(Jim_Interp *interp, int retval) if (return_retval != NULL) *return_retval = retval; - return (retval == ERROR_OK) ? JIM_OK : JIM_ERR; + return (retval == ERROR_OK) ? JIM_OK : retval; } extern struct command_context *global_cmd_ctx; @@ -659,24 +659,7 @@ int command_run_line(struct command_context *context, char *line) } Jim_DeleteAssocData(interp, "context"); } - if (retcode == JIM_ERR) { - if (retval == ERROR_COMMAND_CLOSE_CONNECTION) { - /* Shutdown request is not an error */ - return ERROR_OK; - } else { - /* We do not print the connection closed error message */ - Jim_MakeErrorMessage(interp); - LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL)); - } - if (retval == ERROR_OK) { - /* It wasn't a low level OpenOCD command that failed */ - return ERROR_FAIL; - } - return retval; - } else if (retcode == JIM_EXIT) { - /* ignore. - * exit(Jim_GetExitCode(interp)); */ - } else { + if (retcode == JIM_OK) { const char *result; int reslen; @@ -696,7 +679,22 @@ int command_run_line(struct command_context *context, char *line) LOG_USER_N("\n"); } retval = ERROR_OK; + } else if (retcode == JIM_EXIT) { + /* ignore. + * exit(Jim_GetExitCode(interp)); */ + } else if (retcode == ERROR_COMMAND_CLOSE_CONNECTION) { + return retcode; + } else { + Jim_MakeErrorMessage(interp); + LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL)); + + if (retval == ERROR_OK) { + /* It wasn't a low level OpenOCD command that failed */ + return ERROR_FAIL; + } + return retval; } + return retval; } diff --git a/src/helper/startup.tcl b/src/helper/startup.tcl index 926d26b63..4ca2cabc2 100644 --- a/src/helper/startup.tcl +++ b/src/helper/startup.tcl @@ -16,10 +16,12 @@ proc exit {} { proc ocd_bouncer {name args} { set cmd [format "ocd_%s" $name] set type [eval ocd_command type $cmd $args] + set errcode error if {$type == "native"} { return [eval $cmd $args] } else {if {$type == "simple"} { - if {[catch {eval $cmd $args}] == 0} { + set errcode [catch {eval $cmd $args}] + if {$errcode == 0} { return "" } else { # 'classic' commands output error message as part of progress output @@ -32,7 +34,7 @@ proc ocd_bouncer {name args} { } else { set errmsg [format "invalid subcommand \"%s\"" $args] }}} - return -code error $errmsg + return -code $errcode $errmsg } # Try flipping / and \ to find file if the filename does not diff --git a/src/openocd.c b/src/openocd.c index b0dd21ab2..4d4dc2c83 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -283,7 +283,9 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct return ERROR_FAIL; ret = parse_config_file(cmd_ctx); - if (ret != ERROR_OK) + if (ret == ERROR_COMMAND_CLOSE_CONNECTION) + return ERROR_OK; + else if (ret != ERROR_OK) return ERROR_FAIL; ret = server_init(cmd_ctx); @@ -296,9 +298,15 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct return ERROR_FAIL; } - server_loop(cmd_ctx); + ret = server_loop(cmd_ctx); - return server_quit(); + int last_signal = server_quit(); + if (last_signal != ERROR_OK) + return last_signal; + + if (ret != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; } /* normally this is the main() function entry, but if OpenOCD is linked diff --git a/src/server/server.c b/src/server/server.c index 73d8b5b65..7e90d89fd 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -44,7 +44,8 @@ static struct service *services; -/* shutdown_openocd == 1: exit the main event loop, and quit the debugger */ +/* shutdown_openocd == 1: exit the main event loop, and quit the + * debugger; 2: quit with non-zero return code */ static int shutdown_openocd; /* store received signal to exit application by killing ourselves */ @@ -499,7 +500,7 @@ int server_loop(struct command_context *command_context) #endif } - return ERROR_OK; + return shutdown_openocd != 2 ? ERROR_OK : ERROR_FAIL; } #ifdef _WIN32 @@ -608,6 +609,13 @@ COMMAND_HANDLER(handle_shutdown_command) shutdown_openocd = 1; + if (CMD_ARGC == 1) { + if (!strcmp(CMD_ARGV[0], "error")) { + shutdown_openocd = 2; + return ERROR_FAIL; + } + } + return ERROR_COMMAND_CLOSE_CONNECTION; }