pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Bossart, Nathan <bossartn@amazon.com>
To: Tom Lane <tgl@sss.pgh.pa.us>
Cc: pgsql-hackers@lists.postgresql.org <pgsql-hackers@lists.postgresql.org>
Subject: Re: Improving psql's \password command
Date: Fri, 19 Nov 2021 23:03:26 +0000
Message-ID: <9D3BFA94-DEF2-4B43-B240-8ADC595ECA7A@amazon.com> (raw)
In-Reply-To: <3085404.1637342157@sss.pgh.pa.us>
References: <747443.1635536754@sss.pgh.pa.us>
	<C2787D93-6871-4D93-9CF3-CD7BB489F47F@amazon.com>
	<765509.1635552418@sss.pgh.pa.us>
	<7BAC8A28-148B-4B03-A345-D68071388300@amazon.com>
	<1553329.1636647111@sss.pgh.pa.us>
	<E0C46CDF-46B2-4388-B53B-96EB2CA0F71E@amazon.com>
	<1847699.1636747076@sss.pgh.pa.us>
	<AEA1BA57-BD21-4237-9859-1C04FE38602B@amazon.com>
	<2141902.1636999964@sss.pgh.pa.us>
	<5EDA38EF-C411-4C7D-A9BC-10B1D4584E5E@amazon.com>
	<2152988.1637010233@sss.pgh.pa.us>
	<E4840C66-2FD5-4A0B-8CC9-A09F8B9126B7@amazon.com>
	<2850852.1637194468@sss.pgh.pa.us>
	<450C0AD1-CF21-4056-A9EE-6201E9763FC9@amazon.com>
	<3085404.1637342157@sss.pgh.pa.us>

On 11/19/21, 9:17 AM, "Tom Lane" <tgl@sss.pgh.pa.us> wrote:
> "Bossart, Nathan" <bossartn@amazon.com> writes:
>> Okay, here is an attempt at adding control-C support for \prompt and
>> \connect.  It was reasonably straightforward.  I did have to teach
>> simple_prompt_extended() to add a newline after a cancellation when
>> "echo" is true.
>
> LGTM, pushed after very minor fooling with the comments.

Thanks!

>> I think that's it for psql.  After a quick glance, I didn't see any
>> other obvious candidates for control-C support, but I'll look a little
>> closer to be sure.
>
> Hmm, initdb's prompt-for-superuser-password might need it.
> I think the rest of our frontend programs don't trap SIGINT,
> or at least don't do so while requesting user input.

I'm able to cancel the superuser password prompt in initdb already.
It looks like the signal handlers aren't set up until after
get_su_pwd().  I did find some missing control-C handling in
pg_receivewal/pg_recvlogical, though.  Attached is a patch for those.

Nathan



Attachments:

v1-0001-Add-control-C-handling-for-password-prompts-in-pg.patch (application/octet-stream, 6.0K) download From edd0839967129f7ac8965ebccd9bfe18a7c8967a Mon Sep 17 00:00:00 2001 From: Nathan Bossart <bossartn@amazon.com> Date: Fri, 19 Nov 2021 22:56:13 +0000 Subject: [PATCH v1 1/1] Add control-C handling for password prompts in pg_receivewal and pg_recvlogical. --- src/bin/pg_basebackup/nls.mk | 2 +- src/bin/pg_basebackup/pg_receivewal.c | 11 ++++++++++- src/bin/pg_basebackup/pg_recvlogical.c | 11 ++++++++++- src/bin/pg_basebackup/streamutil.c | 36 ++++++++++++++++++++++++++++------ src/bin/pg_basebackup/streamutil.h | 5 +++++ 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/bin/pg_basebackup/nls.mk b/src/bin/pg_basebackup/nls.mk index 2d521f0683..338048583c 100644 --- a/src/bin/pg_basebackup/nls.mk +++ b/src/bin/pg_basebackup/nls.mk @@ -2,5 +2,5 @@ CATALOG_NAME = pg_basebackup AVAIL_LANGUAGES = cs de es fr he it ja ko pl pt_BR ru sv tr uk vi zh_CN GETTEXT_FILES = $(FRONTEND_COMMON_GETTEXT_FILES) pg_basebackup.c pg_receivewal.c pg_recvlogical.c receivelog.c streamutil.c walmethods.c ../../common/fe_memutils.c ../../common/file_utils.c ../../fe_utils/recovery_gen.c -GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS) simple_prompt tar_set_error +GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS) simple_prompt simple_prompt_extended tar_set_error GETTEXT_FLAGS = $(FRONTEND_COMMON_GETTEXT_FLAGS) diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c index 23cf5f8ec7..ecc068fd9b 100644 --- a/src/bin/pg_basebackup/pg_receivewal.c +++ b/src/bin/pg_basebackup/pg_receivewal.c @@ -649,7 +649,9 @@ StreamLog(void) /* * When sigint is called, just tell the system to exit at the next possible - * moment. + * moment. Since this won't work when blocked on user input (e.g., fgets()), + * we also provide a mechanism to longjmp out of user prompts. While blocked, + * sigint_interrupt_enabled should be set to true. */ #ifndef WIN32 @@ -657,6 +659,13 @@ static void sigint_handler(int signum) { time_to_stop = true; + + /* if we are waiting for input, longjmp out of it */ + if (sigint_interrupt_enabled) + { + sigint_interrupt_enabled = false; + siglongjmp(sigint_interrupt_jmp, 1); + } } #endif diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c index f235d6fecf..8c23abf1f4 100644 --- a/src/bin/pg_basebackup/pg_recvlogical.c +++ b/src/bin/pg_basebackup/pg_recvlogical.c @@ -657,12 +657,21 @@ error: /* * When sigint is called, just tell the system to exit at the next possible - * moment. + * moment. Since this won't work when blocked on user input (e.g., fgets()), + * we also provide a mechanism to longjmp out of user prompts. While blocked, + * sigint_interrupt_enabled should be set to true. */ static void sigint_handler(int signum) { time_to_abort = true; + + /* if we are waiting for input, longjmp out of it */ + if (sigint_interrupt_enabled) + { + sigint_interrupt_enabled = false; + siglongjmp(sigint_interrupt_jmp, 1); + } } /* diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c index 2a3e0c688f..c0adb256b0 100644 --- a/src/bin/pg_basebackup/streamutil.c +++ b/src/bin/pg_basebackup/streamutil.c @@ -52,16 +52,21 @@ char *dbname = NULL; int dbgetpassword = 0; /* 0=auto, -1=never, 1=always */ static char *password = NULL; PGconn *conn = NULL; +volatile bool sigint_interrupt_enabled = false; +sigjmp_buf sigint_interrupt_jmp; /* * Connect to the server. Returns a valid PGconn pointer if connected, * or NULL on non-permanent error. On permanent error, the function will - * call exit(1) directly. + * call exit(1) directly. The password prompt can be canceled via an + * existing SIGINT handler that will longjmp to the place specified by + * sigint_interrupt_jmp only when sigint_interrupt_enabled is true. When + * canceled, this function returns NULL. */ PGconn * GetConnection(void) { - PGconn *tmpconn; + PGconn *tmpconn = NULL; int argcount = 7; /* dbname, replication, fallback_app_name, * host, user, port, password */ int i; @@ -157,10 +162,20 @@ GetConnection(void) /* Get a new password if appropriate */ if (need_password) { + 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 (password) free(password); - password = simple_prompt("Password: ", false); + password = simple_prompt_extended("Password: ", false, &prompt_ctx); need_password = false; + + if (prompt_ctx.canceled) + break; } /* Use (or reuse, on a subsequent connection) password if we have it */ @@ -193,15 +208,24 @@ GetConnection(void) dbgetpassword != -1) { PQfinish(tmpconn); + tmpconn = NULL; need_password = true; } } while (need_password); - if (PQstatus(tmpconn) != CONNECTION_OK) + if (tmpconn == NULL || PQstatus(tmpconn) != CONNECTION_OK) { - pg_log_error("%s", PQerrorMessage(tmpconn)); - PQfinish(tmpconn); + /* + * If tmpconn is NULL, the password prompt was canceled via SIGINT, + * and we don't bother logging an error message. + */ + if (tmpconn != NULL) + { + pg_log_error("%s", PQerrorMessage(tmpconn)); + PQfinish(tmpconn); + } + free(values); free(keywords); if (conn_opts) diff --git a/src/bin/pg_basebackup/streamutil.h b/src/bin/pg_basebackup/streamutil.h index 7918935cb3..2c45fdace4 100644 --- a/src/bin/pg_basebackup/streamutil.h +++ b/src/bin/pg_basebackup/streamutil.h @@ -12,6 +12,8 @@ #ifndef STREAMUTIL_H #define STREAMUTIL_H +#include <setjmp.h> + #include "access/xlogdefs.h" #include "datatype/timestamp.h" #include "libpq-fe.h" @@ -65,4 +67,7 @@ extern bool feTimestampDifferenceExceeds(TimestampTz start_time, TimestampTz sto extern void fe_sendint64(int64 i, char *buf); extern int64 fe_recvint64(char *buf); +extern volatile bool sigint_interrupt_enabled; +extern sigjmp_buf sigint_interrupt_jmp; + #endif /* STREAMUTIL_H */ -- 2.16.6

view thread (22+ messages)  latest in thread

Message-ID: <9D3BFA94-DEF2-4B43-B240-8ADC595ECA7A@amazon.com>
Permalink:  ../9D3BFA94-DEF2-4B43-B240-8ADC595ECA7A@amazon.com/
Also on:    postgresql.org/message-id/9D3BFA94-DEF2-4B43-B240-8ADC595ECA7A@amazon.com

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-hackers@postgresql.org
  Cc: bossartn@amazon.com, tgl@sss.pgh.pa.us, pgsql-hackers@lists.postgresql.org
  Subject: Re: Improving psql's \password command
  In-Reply-To: <9D3BFA94-DEF2-4B43-B240-8ADC595ECA7A@amazon.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox