server: Make "exit" command behave consistently
Before this fix, the "exit" command behaved differently depending on where it was called from: - "exit" in a telnet session: Session disconnected. - "exit" in a Tcl session: Empty response sent but the session remained connected. - "exit" in a script (outside of Telnet or Tcl): OpenOCD exited with code 0. Based on the help and documentation "exit" was apparently not intended for these cases. What's more, if "exit" is allowed in Tcl scripts, user may confuse it with the Tcl's native "exit" command that is not available in OpenOCD (it is shadowed with this OpenOCD's "exit" command). This fix makes the behavior of "exit" consistent: - "exit" in a telnet session: Session disconnected (no change). - "exit" in a Tcl session: Session disconnected (same as for telnet). - "exit" in a script: Notify the user that "exit" is deprecated outside of telnet/tcl but still shut down OpenOCD (to preserve the original behavior). Update the documentation to make it very clear to users when to use "exit" vs. "shutdown". Change-Id: I790495330e1fa705b34097a1347fdc57aaa86de1 Signed-off-by: Jan Matyas <jan.matyas@codasip.com> Reviewed-on: https://review.openocd.org/c/openocd/+/9380 Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Tested-by: jenkins
This commit is contained in:
committed by
Antonio Borneo
parent
5b3db97c42
commit
0c6fe74351
@@ -9529,7 +9529,12 @@ port is 6666.
|
|||||||
@section Server Commands
|
@section Server Commands
|
||||||
|
|
||||||
@deffn {Command} {exit}
|
@deffn {Command} {exit}
|
||||||
Exits the current telnet session.
|
Exits the current telnet or Tcl session but the OpenOCD process remains running.
|
||||||
|
This command should only be used in telnet or Tcl sessions (and not directly
|
||||||
|
in Tcl scripts).
|
||||||
|
|
||||||
|
Note: To terminate the whole OpenOCD process, use the
|
||||||
|
@command{shutdown} command instead.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {help} [string]
|
@deffn {Command} {help} [string]
|
||||||
|
|||||||
@@ -783,6 +783,23 @@ COMMAND_HANDLER(handle_shutdown_command)
|
|||||||
return ERROR_COMMAND_CLOSE_CONNECTION;
|
return ERROR_COMMAND_CLOSE_CONNECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(handle_exit_command)
|
||||||
|
{
|
||||||
|
if (!tcl_is_from_tcl_session(CMD_CTX)
|
||||||
|
&& !telnet_is_from_telnet_session(CMD_CTX)) {
|
||||||
|
LOG_WARNING("DEPRECATED: 'exit' should only be used in telnet or Tcl "
|
||||||
|
"sessions to close the session");
|
||||||
|
LOG_WARNING("Did you mean 'shutdown'?");
|
||||||
|
return command_run_line(CMD_CTX, "shutdown");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CMD_ARGC != 0)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
/* Disconnect telnet / Tcl session */
|
||||||
|
return ERROR_COMMAND_CLOSE_CONNECTION;
|
||||||
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_poll_period_command)
|
COMMAND_HANDLER(handle_poll_period_command)
|
||||||
{
|
{
|
||||||
if (CMD_ARGC == 0)
|
if (CMD_ARGC == 0)
|
||||||
@@ -819,6 +836,13 @@ static const struct command_registration server_command_handlers[] = {
|
|||||||
.usage = "",
|
.usage = "",
|
||||||
.help = "shut the server down",
|
.help = "shut the server down",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "exit",
|
||||||
|
.handler = &handle_exit_command,
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.usage = "",
|
||||||
|
.help = "exit (disconnect) telnet or Tcl session",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "poll_period",
|
.name = "poll_period",
|
||||||
.handler = &handle_poll_period_command,
|
.handler = &handle_poll_period_command,
|
||||||
|
|||||||
@@ -230,12 +230,22 @@ static int tcl_input(struct connection *connection)
|
|||||||
#undef ESTR
|
#undef ESTR
|
||||||
} else {
|
} else {
|
||||||
tclc->tc_line[tclc->tc_lineoffset-1] = '\0';
|
tclc->tc_line[tclc->tc_lineoffset-1] = '\0';
|
||||||
command_run_line(connection->cmd_ctx, tclc->tc_line);
|
retval = command_run_line(connection->cmd_ctx, tclc->tc_line);
|
||||||
|
|
||||||
|
if (retval == ERROR_COMMAND_CLOSE_CONNECTION) {
|
||||||
|
/* "shutdown" or "exit" executed.
|
||||||
|
* Send an empty response - just the response termination character.
|
||||||
|
*/
|
||||||
|
tcl_output(connection, "\x1a", 1);
|
||||||
|
return ERROR_SERVER_REMOTE_CLOSED;
|
||||||
|
}
|
||||||
|
|
||||||
result = Jim_GetString(Jim_GetResult(interp), &reslen);
|
result = Jim_GetString(Jim_GetResult(interp), &reslen);
|
||||||
retval = tcl_output(connection, result, reslen);
|
retval = tcl_output(connection, result, reslen);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
/* Always output ctrl-z as end of line to allow multiline results */
|
|
||||||
|
/* Signal the end of response by a termination character (ctrl-z) */
|
||||||
tcl_output(connection, "\x1a", 1);
|
tcl_output(connection, "\x1a", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,6 +294,15 @@ int tcl_init(void)
|
|||||||
return add_service(&tcl_service_driver, tcl_port, CONNECTION_LIMIT_UNLIMITED, NULL);
|
return add_service(&tcl_service_driver, tcl_port, CONNECTION_LIMIT_UNLIMITED, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tcl_is_from_tcl_session(struct command_context *cmd_ctx)
|
||||||
|
{
|
||||||
|
if (!cmd_ctx->output_handler_priv)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct connection *conn = (struct connection *)cmd_ctx->output_handler_priv;
|
||||||
|
return strcmp(conn->service->name, "tcl") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_tcl_port_command)
|
COMMAND_HANDLER(handle_tcl_port_command)
|
||||||
{
|
{
|
||||||
return CALL_COMMAND_HANDLER(server_pipe_command, &tcl_port);
|
return CALL_COMMAND_HANDLER(server_pipe_command, &tcl_port);
|
||||||
@@ -297,7 +316,7 @@ COMMAND_HANDLER(handle_tcl_notifications_command)
|
|||||||
if (CMD_CTX->output_handler_priv)
|
if (CMD_CTX->output_handler_priv)
|
||||||
connection = CMD_CTX->output_handler_priv;
|
connection = CMD_CTX->output_handler_priv;
|
||||||
|
|
||||||
if (connection && !strcmp(connection->service->name, "tcl")) {
|
if (connection && tcl_is_from_tcl_session(CMD_CTX)) {
|
||||||
tclc = connection->priv;
|
tclc = connection->priv;
|
||||||
return CALL_COMMAND_HANDLER(handle_command_parse_bool, &tclc->tc_notify, "Target Notification output ");
|
return CALL_COMMAND_HANDLER(handle_command_parse_bool, &tclc->tc_notify, "Target Notification output ");
|
||||||
} else {
|
} else {
|
||||||
@@ -314,7 +333,7 @@ COMMAND_HANDLER(handle_tcl_trace_command)
|
|||||||
if (CMD_CTX->output_handler_priv)
|
if (CMD_CTX->output_handler_priv)
|
||||||
connection = CMD_CTX->output_handler_priv;
|
connection = CMD_CTX->output_handler_priv;
|
||||||
|
|
||||||
if (connection && !strcmp(connection->service->name, "tcl")) {
|
if (connection && tcl_is_from_tcl_session(CMD_CTX)) {
|
||||||
tclc = connection->priv;
|
tclc = connection->priv;
|
||||||
return CALL_COMMAND_HANDLER(handle_command_parse_bool, &tclc->tc_trace, "Target trace output ");
|
return CALL_COMMAND_HANDLER(handle_command_parse_bool, &tclc->tc_trace, "Target trace output ");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -12,5 +12,6 @@
|
|||||||
int tcl_init(void);
|
int tcl_init(void);
|
||||||
int tcl_register_commands(struct command_context *cmd_ctx);
|
int tcl_register_commands(struct command_context *cmd_ctx);
|
||||||
void tcl_service_free(void);
|
void tcl_service_free(void);
|
||||||
|
bool tcl_is_from_tcl_session(struct command_context *ctx);
|
||||||
|
|
||||||
#endif /* OPENOCD_SERVER_TCL_SERVER_H */
|
#endif /* OPENOCD_SERVER_TCL_SERVER_H */
|
||||||
|
|||||||
@@ -519,6 +519,7 @@ static int telnet_exec_line(struct connection *connection)
|
|||||||
t_con->prompt_visible = true;
|
t_con->prompt_visible = true;
|
||||||
|
|
||||||
if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
|
if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
|
||||||
|
/* "shutdown" or "exit" executed. */
|
||||||
return ERROR_SERVER_REMOTE_CLOSED;
|
return ERROR_SERVER_REMOTE_CLOSED;
|
||||||
|
|
||||||
/* the prompt is always placed at the line beginning */
|
/* the prompt is always placed at the line beginning */
|
||||||
@@ -967,16 +968,16 @@ int telnet_init(char *banner)
|
|||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool telnet_is_from_telnet_session(struct command_context *cmd_ctx)
|
||||||
|
{
|
||||||
|
return cmd_ctx->output_handler == telnet_output;
|
||||||
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_telnet_port_command)
|
COMMAND_HANDLER(handle_telnet_port_command)
|
||||||
{
|
{
|
||||||
return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port);
|
return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_exit_command)
|
|
||||||
{
|
|
||||||
return ERROR_COMMAND_CLOSE_CONNECTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct command_registration telnet_subcommand_handlers[] = {
|
static const struct command_registration telnet_subcommand_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "port",
|
.name = "port",
|
||||||
@@ -991,13 +992,6 @@ static const struct command_registration telnet_subcommand_handlers[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct command_registration telnet_command_handlers[] = {
|
static const struct command_registration telnet_command_handlers[] = {
|
||||||
{
|
|
||||||
.name = "exit",
|
|
||||||
.handler = handle_exit_command,
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.usage = "",
|
|
||||||
.help = "exit telnet session",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.name = "telnet",
|
.name = "telnet",
|
||||||
.chain = telnet_subcommand_handlers,
|
.chain = telnet_subcommand_handlers,
|
||||||
|
|||||||
@@ -54,5 +54,6 @@ struct telnet_service {
|
|||||||
int telnet_init(char *banner);
|
int telnet_init(char *banner);
|
||||||
int telnet_register_commands(struct command_context *command_context);
|
int telnet_register_commands(struct command_context *command_context);
|
||||||
void telnet_service_free(void);
|
void telnet_service_free(void);
|
||||||
|
bool telnet_is_from_telnet_session(struct command_context *cmd_ctx);
|
||||||
|
|
||||||
#endif /* OPENOCD_SERVER_TELNET_SERVER_H */
|
#endif /* OPENOCD_SERVER_TELNET_SERVER_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user