Allow psql's other uses of simple_prompt() to be interrupted by ^C.

This fills in the work left un-done by 5f1148224.  \prompt can
be canceled out of now, and so can password prompts issued during
\connect.  (We don't need to do anything for password prompts
issued during startup, because we aren't yet trapping SIGINT
at that point.)

Nathan Bossart

Discussion: https://postgr.es/m/747443.1635536754@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2021-11-19 12:11:38 -05:00
parent 3b34645678
commit 46d665bc26
3 changed files with 43 additions and 11 deletions

View File

@ -2132,6 +2132,12 @@ exec_command_prompt(PsqlScanState scan_state, bool active_branch,
else
{
char *result;
PromptInterruptContext prompt_ctx;
/* Set up to let SIGINT cancel simple_prompt_extended() */
prompt_ctx.jmpbuf = sigint_interrupt_jmp;
prompt_ctx.enabled = &sigint_interrupt_enabled;
prompt_ctx.canceled = false;
if (arg2)
{
@ -2143,7 +2149,7 @@ exec_command_prompt(PsqlScanState scan_state, bool active_branch,
if (!pset.inputfile)
{
result = simple_prompt(prompt_text, true);
result = simple_prompt_extended(prompt_text, true, &prompt_ctx);
}
else
{
@ -2161,8 +2167,8 @@ exec_command_prompt(PsqlScanState scan_state, bool active_branch,
}
}
if (result &&
!SetVariable(pset.vars, opt, result))
if (prompt_ctx.canceled ||
(result && !SetVariable(pset.vars, opt, result)))
success = false;
if (result)
@ -3058,24 +3064,36 @@ copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf)
/*
* Ask the user for a password; 'username' is the username the
* password is for, if one has been explicitly specified. Returns a
* malloc'd string.
* password is for, if one has been explicitly specified.
* Returns a malloc'd string.
* If 'canceled' is provided, *canceled will be set to true if the prompt
* is canceled via SIGINT, and to false otherwise.
*/
static char *
prompt_for_password(const char *username)
prompt_for_password(const char *username, bool *canceled)
{
char *result;
PromptInterruptContext prompt_ctx;
/* Set up to let SIGINT cancel simple_prompt_extended() */
prompt_ctx.jmpbuf = sigint_interrupt_jmp;
prompt_ctx.enabled = &sigint_interrupt_enabled;
prompt_ctx.canceled = false;
if (username == NULL || username[0] == '\0')
result = simple_prompt("Password: ", false);
result = simple_prompt_extended("Password: ", false, &prompt_ctx);
else
{
char *prompt_text;
prompt_text = psprintf(_("Password for user %s: "), username);
result = simple_prompt(prompt_text, false);
result = simple_prompt_extended(prompt_text, false, &prompt_ctx);
free(prompt_text);
}
if (canceled)
*canceled = prompt_ctx.canceled;
return result;
}
@ -3331,6 +3349,8 @@ do_connect(enum trivalue reuse_previous_specification,
*/
if (pset.getPassword == TRI_YES && success)
{
bool canceled = false;
/*
* If a connstring or URI is provided, we don't know which username
* will be used, since we haven't dug that out of the connstring.
@ -3338,7 +3358,9 @@ do_connect(enum trivalue reuse_previous_specification,
* not seem worth working harder, since this getPassword setting is
* normally only used in noninteractive cases.
*/
password = prompt_for_password(has_connection_string ? NULL : user);
password = prompt_for_password(has_connection_string ? NULL : user,
&canceled);
success = !canceled;
}
/*
@ -3417,13 +3439,16 @@ do_connect(enum trivalue reuse_previous_specification,
*/
if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
{
bool canceled = false;
/*
* Prompt for password using the username we actually connected
* with --- it might've come out of "dbname" rather than "user".
*/
password = prompt_for_password(PQuser(n_conn));
password = prompt_for_password(PQuser(n_conn), &canceled);
PQfinish(n_conn);
n_conn = NULL;
success = !canceled;
continue;
}

View File

@ -239,7 +239,8 @@ main(int argc, char *argv[])
/*
* We can't be sure yet of the username that will be used, so don't
* offer a potentially wrong one. Typical uses of this option are
* noninteractive anyway.
* noninteractive anyway. (Note: since we've not yet set up our
* cancel handler, there's no need to use simple_prompt_extended.)
*/
password = simple_prompt("Password: ", false);
}

View File

@ -164,6 +164,12 @@ simple_prompt_extended(const char *prompt, bool echo,
fflush(termout);
#endif
}
else if (prompt_ctx && prompt_ctx->canceled)
{
/* also echo \n if prompt was canceled */
fputs("\n", termout);
fflush(termout);
}
if (termin != stdin)
{