Skip to content

Commit 46d665b

Browse files
committed
Allow psql's other uses of simple_prompt() to be interrupted by ^C.
This fills in the work left un-done by 5f11482. \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
1 parent 3b34645 commit 46d665b

File tree

3 files changed

+43
-11
lines changed

3 files changed

+43
-11
lines changed

src/bin/psql/command.c

+35-10
Original file line numberDiff line numberDiff line change
@@ -2132,6 +2132,12 @@ exec_command_prompt(PsqlScanState scan_state, bool active_branch,
21322132
else
21332133
{
21342134
char *result;
2135+
PromptInterruptContext prompt_ctx;
2136+
2137+
/* Set up to let SIGINT cancel simple_prompt_extended() */
2138+
prompt_ctx.jmpbuf = sigint_interrupt_jmp;
2139+
prompt_ctx.enabled = &sigint_interrupt_enabled;
2140+
prompt_ctx.canceled = false;
21352141

21362142
if (arg2)
21372143
{
@@ -2143,7 +2149,7 @@ exec_command_prompt(PsqlScanState scan_state, bool active_branch,
21432149

21442150
if (!pset.inputfile)
21452151
{
2146-
result = simple_prompt(prompt_text, true);
2152+
result = simple_prompt_extended(prompt_text, true, &prompt_ctx);
21472153
}
21482154
else
21492155
{
@@ -2161,8 +2167,8 @@ exec_command_prompt(PsqlScanState scan_state, bool active_branch,
21612167
}
21622168
}
21632169

2164-
if (result &&
2165-
!SetVariable(pset.vars, opt, result))
2170+
if (prompt_ctx.canceled ||
2171+
(result && !SetVariable(pset.vars, opt, result)))
21662172
success = false;
21672173

21682174
if (result)
@@ -3058,24 +3064,36 @@ copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf)
30583064

30593065
/*
30603066
* Ask the user for a password; 'username' is the username the
3061-
* password is for, if one has been explicitly specified. Returns a
3062-
* malloc'd string.
3067+
* password is for, if one has been explicitly specified.
3068+
* Returns a malloc'd string.
3069+
* If 'canceled' is provided, *canceled will be set to true if the prompt
3070+
* is canceled via SIGINT, and to false otherwise.
30633071
*/
30643072
static char *
3065-
prompt_for_password(const char *username)
3073+
prompt_for_password(const char *username, bool *canceled)
30663074
{
30673075
char *result;
3076+
PromptInterruptContext prompt_ctx;
3077+
3078+
/* Set up to let SIGINT cancel simple_prompt_extended() */
3079+
prompt_ctx.jmpbuf = sigint_interrupt_jmp;
3080+
prompt_ctx.enabled = &sigint_interrupt_enabled;
3081+
prompt_ctx.canceled = false;
30683082

30693083
if (username == NULL || username[0] == '\0')
3070-
result = simple_prompt("Password: ", false);
3084+
result = simple_prompt_extended("Password: ", false, &prompt_ctx);
30713085
else
30723086
{
30733087
char *prompt_text;
30743088

30753089
prompt_text = psprintf(_("Password for user %s: "), username);
3076-
result = simple_prompt(prompt_text, false);
3090+
result = simple_prompt_extended(prompt_text, false, &prompt_ctx);
30773091
free(prompt_text);
30783092
}
3093+
3094+
if (canceled)
3095+
*canceled = prompt_ctx.canceled;
3096+
30793097
return result;
30803098
}
30813099

@@ -3331,14 +3349,18 @@ do_connect(enum trivalue reuse_previous_specification,
33313349
*/
33323350
if (pset.getPassword == TRI_YES && success)
33333351
{
3352+
bool canceled = false;
3353+
33343354
/*
33353355
* If a connstring or URI is provided, we don't know which username
33363356
* will be used, since we haven't dug that out of the connstring.
33373357
* Don't risk issuing a misleading prompt. As in startup.c, it does
33383358
* not seem worth working harder, since this getPassword setting is
33393359
* normally only used in noninteractive cases.
33403360
*/
3341-
password = prompt_for_password(has_connection_string ? NULL : user);
3361+
password = prompt_for_password(has_connection_string ? NULL : user,
3362+
&canceled);
3363+
success = !canceled;
33423364
}
33433365

33443366
/*
@@ -3417,13 +3439,16 @@ do_connect(enum trivalue reuse_previous_specification,
34173439
*/
34183440
if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
34193441
{
3442+
bool canceled = false;
3443+
34203444
/*
34213445
* Prompt for password using the username we actually connected
34223446
* with --- it might've come out of "dbname" rather than "user".
34233447
*/
3424-
password = prompt_for_password(PQuser(n_conn));
3448+
password = prompt_for_password(PQuser(n_conn), &canceled);
34253449
PQfinish(n_conn);
34263450
n_conn = NULL;
3451+
success = !canceled;
34273452
continue;
34283453
}
34293454

src/bin/psql/startup.c

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

src/common/sprompt.c

+6
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ simple_prompt_extended(const char *prompt, bool echo,
164164
fflush(termout);
165165
#endif
166166
}
167+
else if (prompt_ctx && prompt_ctx->canceled)
168+
{
169+
/* also echo \n if prompt was canceled */
170+
fputs("\n", termout);
171+
fflush(termout);
172+
}
167173

168174
if (termin != stdin)
169175
{

0 commit comments

Comments
 (0)