Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5f11482

Browse files
committed
Provide a variant of simple_prompt() that can be interrupted by ^C.
Up to now, you couldn't escape out of psql's \password commandby typing control-C (or other local spelling of SIGINT). Thisis pretty user-unfriendly, so improve it. To do so, we have tomodify the functions provided by pg_get_line.c; but we don'twant to mess with psql's SIGINT handler setup, so provide anAPI that lets that handler cause the cancel to occur.This relies on the assumption that we won't do any major harm bylongjmp'ing out of fgets(). While that's obviously a little shaky,we've long had the same assumption in the main input loop, and fewissues have been reported.psql has some other simple_prompt() calls that could usefullybe improved the same way; for now, just deal with \password.Nathan Bossart, minor tweaks by meDiscussion:https://postgr.es/m/747443.1635536754@sss.pgh.pa.us
1 parenta148f8b commit5f11482

File tree

7 files changed

+100
-19
lines changed

7 files changed

+100
-19
lines changed

‎src/backend/libpq/hba.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel)
500500
/* Collect the next input line, handling backslash continuations */
501501
resetStringInfo(&buf);
502502

503-
while (pg_get_line_append(file,&buf))
503+
while (pg_get_line_append(file,&buf,NULL))
504504
{
505505
/* Strip trailing newline, including \r in case we're on Windows */
506506
buf.len=pg_strip_crlf(buf.data);

‎src/bin/initdb/initdb.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1497,7 +1497,7 @@ get_su_pwd(void)
14971497
pwfilename);
14981498
exit(1);
14991499
}
1500-
pwd1=pg_get_line(pwf);
1500+
pwd1=pg_get_line(pwf,NULL);
15011501
if (!pwd1)
15021502
{
15031503
if (ferror(pwf))

‎src/bin/psql/command.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,9 +2025,10 @@ exec_command_password(PsqlScanState scan_state, bool active_branch)
20252025
{
20262026
char*user=psql_scan_slash_option(scan_state,
20272027
OT_SQLID,NULL, true);
2028-
char*pw1;
2029-
char*pw2;
2028+
char*pw1=NULL;
2029+
char*pw2=NULL;
20302030
PQExpBufferDatabuf;
2031+
PromptInterruptContextprompt_ctx;
20312032

20322033
if (user==NULL)
20332034
{
@@ -2042,13 +2043,24 @@ exec_command_password(PsqlScanState scan_state, bool active_branch)
20422043
PQclear(res);
20432044
}
20442045

2046+
/* Set up to let SIGINT cancel simple_prompt_extended() */
2047+
prompt_ctx.jmpbuf=sigint_interrupt_jmp;
2048+
prompt_ctx.enabled=&sigint_interrupt_enabled;
2049+
prompt_ctx.canceled= false;
2050+
20452051
initPQExpBuffer(&buf);
20462052
printfPQExpBuffer(&buf,_("Enter new password for user \"%s\": "),user);
20472053

2048-
pw1=simple_prompt(buf.data, false);
2049-
pw2=simple_prompt("Enter it again: ", false);
2054+
pw1=simple_prompt_extended(buf.data, false,&prompt_ctx);
2055+
if (!prompt_ctx.canceled)
2056+
pw2=simple_prompt_extended("Enter it again: ", false,&prompt_ctx);
20502057

2051-
if (strcmp(pw1,pw2)!=0)
2058+
if (prompt_ctx.canceled)
2059+
{
2060+
/* fail silently */
2061+
success= false;
2062+
}
2063+
elseif (strcmp(pw1,pw2)!=0)
20522064
{
20532065
pg_log_error("Passwords didn't match.");
20542066
success= false;
@@ -2081,8 +2093,10 @@ exec_command_password(PsqlScanState scan_state, bool active_branch)
20812093
}
20822094

20832095
free(user);
2084-
free(pw1);
2085-
free(pw2);
2096+
if (pw1)
2097+
free(pw1);
2098+
if (pw2)
2099+
free(pw2);
20862100
termPQExpBuffer(&buf);
20872101
}
20882102
else

‎src/bin/psql/nls.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ GETTEXT_FILES = $(FRONTEND_COMMON_GETTEXT_FILES) \
1010
../../common/exec.c ../../common/fe_memutils.c ../../common/username.c\
1111
../../common/wait_error.c
1212
GETTEXT_TRIGGERS =$(FRONTEND_COMMON_GETTEXT_TRIGGERS)\
13-
N_ simple_prompt
13+
N_ simple_prompt simple_prompt_extended
1414
GETTEXT_FLAGS =$(FRONTEND_COMMON_GETTEXT_FLAGS)

‎src/common/pg_get_line.c

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include"postgres_fe.h"
1919
#endif
2020

21+
#include<setjmp.h>
22+
2123
#include"common/string.h"
2224
#include"lib/stringinfo.h"
2325

@@ -47,15 +49,20 @@
4749
* to collect lots of long-lived data. A less memory-hungry option
4850
* is to use pg_get_line_buf() or pg_get_line_append() in a loop,
4951
* then pstrdup() each line.
52+
*
53+
* prompt_ctx can optionally be provided to allow this function to be
54+
* canceled via an existing SIGINT signal handler that will longjmp to the
55+
* specified place only when *(prompt_ctx->enabled) is true. If canceled,
56+
* this function returns NULL, and prompt_ctx->canceled is set to true.
5057
*/
5158
char*
52-
pg_get_line(FILE*stream)
59+
pg_get_line(FILE*stream,PromptInterruptContext*prompt_ctx)
5360
{
5461
StringInfoDatabuf;
5562

5663
initStringInfo(&buf);
5764

58-
if (!pg_get_line_append(stream,&buf))
65+
if (!pg_get_line_append(stream,&buf,prompt_ctx))
5966
{
6067
/* ensure that free() doesn't mess up errno */
6168
intsave_errno=errno;
@@ -89,7 +96,7 @@ pg_get_line_buf(FILE *stream, StringInfo buf)
8996
{
9097
/* We just need to drop any data from the previous call */
9198
resetStringInfo(buf);
92-
returnpg_get_line_append(stream,buf);
99+
returnpg_get_line_append(stream,buf,NULL);
93100
}
94101

95102
/*
@@ -107,15 +114,48 @@ pg_get_line_buf(FILE *stream, StringInfo buf)
107114
*
108115
* In the false-result case, the contents of *buf are logically unmodified,
109116
* though it's possible that the buffer has been resized.
117+
*
118+
* prompt_ctx can optionally be provided to allow this function to be
119+
* canceled via an existing SIGINT signal handler that will longjmp to the
120+
* specified place only when *(prompt_ctx->enabled) is true. If canceled,
121+
* this function returns false, and prompt_ctx->canceled is set to true.
110122
*/
111123
bool
112-
pg_get_line_append(FILE*stream,StringInfobuf)
124+
pg_get_line_append(FILE*stream,StringInfobuf,
125+
PromptInterruptContext*prompt_ctx)
113126
{
114127
intorig_len=buf->len;
115128

116-
/* Read some data, appending it to whatever we already have */
117-
while (fgets(buf->data+buf->len,buf->maxlen-buf->len,stream)!=NULL)
129+
if (prompt_ctx&&sigsetjmp(*((sigjmp_buf*)prompt_ctx->jmpbuf),1)!=0)
118130
{
131+
/* Got here with longjmp */
132+
prompt_ctx->canceled= true;
133+
/* Discard any data we collected before detecting error */
134+
buf->len=orig_len;
135+
buf->data[orig_len]='\0';
136+
return false;
137+
}
138+
139+
/* Loop until newline or EOF/error */
140+
for (;;)
141+
{
142+
char*res;
143+
144+
/* Enable longjmp while waiting for input */
145+
if (prompt_ctx)
146+
*(prompt_ctx->enabled)= true;
147+
148+
/* Read some data, appending it to whatever we already have */
149+
res=fgets(buf->data+buf->len,buf->maxlen-buf->len,stream);
150+
151+
/* Disable longjmp again, then break if fgets failed */
152+
if (prompt_ctx)
153+
*(prompt_ctx->enabled)= false;
154+
155+
if (res==NULL)
156+
break;
157+
158+
/* Got data, so update buf->len */
119159
buf->len+=strlen(buf->data+buf->len);
120160

121161
/* Done if we have collected a newline */

‎src/common/sprompt.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,22 @@
3636
*/
3737
char*
3838
simple_prompt(constchar*prompt,boolecho)
39+
{
40+
returnsimple_prompt_extended(prompt,echo,NULL);
41+
}
42+
43+
/*
44+
* simple_prompt_extended
45+
*
46+
* This is the same as simple_prompt(), except that prompt_ctx can
47+
* optionally be provided to allow this function to be canceled via an
48+
* existing SIGINT signal handler that will longjmp to the specified place
49+
* only when *(prompt_ctx->enabled) is true. If canceled, this function
50+
* returns an empty string, and prompt_ctx->canceled is set to true.
51+
*/
52+
char*
53+
simple_prompt_extended(constchar*prompt,boolecho,
54+
PromptInterruptContext*prompt_ctx)
3955
{
4056
char*result;
4157
FILE*termin,
@@ -126,7 +142,7 @@ simple_prompt(const char *prompt, bool echo)
126142
fflush(termout);
127143
}
128144

129-
result=pg_get_line(termin);
145+
result=pg_get_line(termin,prompt_ctx);
130146

131147
/* If we failed to read anything, just return an empty string */
132148
if (result==NULL)

‎src/include/common/string.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212

1313
structStringInfoData;/* avoid including stringinfo.h here */
1414

15+
typedefstructPromptInterruptContext
16+
{
17+
/* To avoid including <setjmp.h> here, jmpbuf is declared "void *" */
18+
void*jmpbuf;/* existing longjmp buffer */
19+
volatilebool*enabled;/* flag that enables longjmp-on-interrupt */
20+
boolcanceled;/* indicates whether cancellation occurred */
21+
}PromptInterruptContext;
22+
1523
/* functions in src/common/string.c */
1624
externboolpg_str_endswith(constchar*str,constchar*end);
1725
externintstrtoint(constchar*pg_restrictstr,char**pg_restrictendptr,
@@ -21,11 +29,14 @@ extern intpg_strip_crlf(char *str);
2129
externboolpg_is_ascii(constchar*str);
2230

2331
/* functions in src/common/pg_get_line.c */
24-
externchar*pg_get_line(FILE*stream);
32+
externchar*pg_get_line(FILE*stream,PromptInterruptContext*prompt_ctx);
2533
externboolpg_get_line_buf(FILE*stream,structStringInfoData*buf);
26-
externboolpg_get_line_append(FILE*stream,structStringInfoData*buf);
34+
externboolpg_get_line_append(FILE*stream,structStringInfoData*buf,
35+
PromptInterruptContext*prompt_ctx);
2736

2837
/* functions in src/common/sprompt.c */
2938
externchar*simple_prompt(constchar*prompt,boolecho);
39+
externchar*simple_prompt_extended(constchar*prompt,boolecho,
40+
PromptInterruptContext*prompt_ctx);
3041

3142
#endif/* COMMON_STRING_H */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp