git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jeff King <peff@peff.net>
To: Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org
Subject: [PATCHv2 5/9] add generic terminal prompt function
Date: Sat, 10 Dec 2011 05:41:01 -0500	[thread overview]
Message-ID: <20111210104101.GE16648@sigill.intra.peff.net> (raw)
In-Reply-To: <20111210103943.GA16478@sigill.intra.peff.net>

When we need to prompt the user for input interactively, we
want to access their terminal directly. We can't rely on
stdio because it may be connected to pipes or files, rather
than the terminal. Instead, we use "getpass()", because it
abstracts the idea of prompting and reading from the
terminal.  However, it has some problems:

  1. It never echoes the typed characters, which makes it OK
     for passwords but annoying for other input (like usernames).

  2. Some implementations of getpass() have an extremely
     small input buffer (e.g., Solaris 8 is reported to
     support only 8 characters).

  3. Some implementations of getpass() will fall back to
     reading from stdin (e.g., glibc). We explicitly don't
     want this, because our stdin may be connected to a pipe
     speaking a particular protocol, and reading will
     disrupt the protocol flow (e.g., the remote-curl
     helper).

  4. Some implementations of getpass() turn off signals, so
     that hitting "^C" on the terminal does not break out of
     the password prompt. This can be a mild annoyance.

Instead, let's provide an abstract "git_terminal_prompt"
function that addresses these concerns. This patch includes
an implementation based on /dev/tty, enabled by setting
HAVE_DEV_TTY. The fallback is to use getpass() as before.

Signed-off-by: Jeff King <peff@peff.net>
---
 Makefile          |    9 ++++++
 compat/terminal.c |   81 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 compat/terminal.h |    6 ++++
 3 files changed, 96 insertions(+), 0 deletions(-)
 create mode 100644 compat/terminal.c
 create mode 100644 compat/terminal.h

diff --git a/Makefile b/Makefile
index 5201bea..4ef6ba5 100644
--- a/Makefile
+++ b/Makefile
@@ -227,6 +227,9 @@ all::
 #
 # Define NO_REGEX if you have no or inferior regex support in your C library.
 #
+# Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the
+# user.
+#
 # Define GETTEXT_POISON if you are debugging the choice of strings marked
 # for translation.  In a GETTEXT_POISON build, you can turn all strings marked
 # for translation into gibberish by setting the GIT_GETTEXT_POISON variable
@@ -523,6 +526,7 @@ LIB_H += compat/bswap.h
 LIB_H += compat/cygwin.h
 LIB_H += compat/mingw.h
 LIB_H += compat/obstack.h
+LIB_H += compat/terminal.h
 LIB_H += compat/win32/pthread.h
 LIB_H += compat/win32/syslog.h
 LIB_H += compat/win32/poll.h
@@ -612,6 +616,7 @@ LIB_OBJS += color.o
 LIB_OBJS += combine-diff.o
 LIB_OBJS += commit.o
 LIB_OBJS += compat/obstack.o
+LIB_OBJS += compat/terminal.o
 LIB_OBJS += config.o
 LIB_OBJS += connect.o
 LIB_OBJS += connected.o
@@ -1642,6 +1647,10 @@ ifdef HAVE_PATHS_H
 	BASIC_CFLAGS += -DHAVE_PATHS_H
 endif
 
+ifdef HAVE_DEV_TTY
+	BASIC_CFLAGS += -DHAVE_DEV_TTY
+endif
+
 ifdef DIR_HAS_BSD_GROUP_SEMANTICS
 	COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
 endif
diff --git a/compat/terminal.c b/compat/terminal.c
new file mode 100644
index 0000000..6d16c8f
--- /dev/null
+++ b/compat/terminal.c
@@ -0,0 +1,81 @@
+#include "git-compat-util.h"
+#include "compat/terminal.h"
+#include "sigchain.h"
+#include "strbuf.h"
+
+#ifdef HAVE_DEV_TTY
+
+static int term_fd = -1;
+static struct termios old_term;
+
+static void restore_term(void)
+{
+	if (term_fd < 0)
+		return;
+
+	tcsetattr(term_fd, TCSAFLUSH, &old_term);
+	term_fd = -1;
+}
+
+static void restore_term_on_signal(int sig)
+{
+	restore_term();
+	sigchain_pop(sig);
+	raise(sig);
+}
+
+char *git_terminal_prompt(const char *prompt, int echo)
+{
+	static struct strbuf buf = STRBUF_INIT;
+	int r;
+	FILE *fh;
+
+	fh = fopen("/dev/tty", "w+");
+	if (!fh)
+		return NULL;
+
+	if (!echo) {
+		struct termios t;
+
+		if (tcgetattr(fileno(fh), &t) < 0) {
+			fclose(fh);
+			return NULL;
+		}
+
+		old_term = t;
+		term_fd = fileno(fh);
+		sigchain_push_common(restore_term_on_signal);
+
+		t.c_lflag &= ~ECHO;
+		if (tcsetattr(fileno(fh), TCSAFLUSH, &t) < 0) {
+			term_fd = -1;
+			fclose(fh);
+			return NULL;
+		}
+	}
+
+	fputs(prompt, fh);
+	fflush(fh);
+
+	r = strbuf_getline(&buf, fh, '\n');
+	if (!echo) {
+		putc('\n', fh);
+		fflush(fh);
+	}
+
+	restore_term();
+	fclose(fh);
+
+	if (r == EOF)
+		return NULL;
+	return buf.buf;
+}
+
+#else
+
+char *git_terminal_prompt(const char *prompt, int echo)
+{
+	return getpass(prompt);
+}
+
+#endif
diff --git a/compat/terminal.h b/compat/terminal.h
new file mode 100644
index 0000000..97db7cd
--- /dev/null
+++ b/compat/terminal.h
@@ -0,0 +1,6 @@
+#ifndef COMPAT_TERMINAL_H
+#define COMPAT_TERMINAL_H
+
+char *git_terminal_prompt(const char *prompt, int echo);
+
+#endif /* COMPAT_TERMINAL_H */
-- 
1.7.8.rc2.40.gaf387

  parent reply	other threads:[~2011-12-10 10:41 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-12-10 10:28 [PATCHv3 0/13] credential helpers Jeff King
2011-12-10 10:30 ` [PATCHv3 01/13] test-lib: add test_config_global variant Jeff King
2011-12-10 10:30 ` [PATCHv3 02/13] t5550: fix typo Jeff King
2011-12-10 10:31 ` [PATCHv3 03/13] introduce credentials API Jeff King
2011-12-10 11:43   ` Jakub Narebski
2011-12-10 19:48     ` Jeff King
2011-12-10 10:31 ` [PATCHv3 04/13] credential: add function for parsing url components Jeff King
2011-12-10 10:31 ` [PATCHv3 05/13] http: use credential API to get passwords Jeff King
2011-12-10 10:31 ` [PATCHv3 06/13] credential: apply helper config Jeff King
2011-12-10 10:31 ` [PATCHv3 07/13] credential: add credential.*.username Jeff King
2011-12-10 10:31 ` [PATCHv3 08/13] credential: make relevance of http path configurable Jeff King
2011-12-10 11:50   ` Jakub Narebski
2011-12-10 19:50     ` Jeff King
2011-12-10 10:31 ` [PATCHv3 09/13] docs: end-user documentation for the credential subsystem Jeff King
2011-12-10 10:34 ` [PATCHv3 10/13] credentials: add "cache" helper Jeff King
2012-01-10  1:50   ` Jonathan Nieder
2012-01-10  4:44     ` Jeff King
2012-01-10  4:57       ` Jeff King
2012-01-10 16:59         ` Junio C Hamano
2012-01-17  6:02         ` Jeff King
2012-01-17  6:51           ` Junio C Hamano
2012-01-10 17:44       ` Jonathan Nieder
2012-01-10 17:53         ` Jeff King
2012-01-11 23:50           ` Jonathan Nieder
2012-01-12  3:07             ` Jeff King
2011-12-10 10:34 ` [PATCHv3 11/13] strbuf: add strbuf_add*_urlencode Jeff King
2011-12-10 11:57   ` Jakub Narebski
2011-12-10 20:09     ` Jeff King
2011-12-10 10:34 ` [PATCHv3 12/13] credentials: add "store" helper Jeff King
2011-12-10 10:35 ` [PATCHv3 13/13] t: add test harness for external credential helpers Jeff King
2011-12-10 10:39 ` [PATCHv2 0/9] echo characters in username prompt Jeff King
2011-12-10 10:40   ` [PATCHv2 1/9] imap-send: avoid buffer overflow Jeff King
2011-12-10 10:40   ` [PATCHv2 2/9] imap-send: don't check return value of git_getpass Jeff King
2011-12-10 10:40   ` [PATCHv2 3/9] move git_getpass to its own source file Jeff King
2011-12-10 10:40   ` [PATCHv2 4/9] refactor git_getpass into generic prompt function Jeff King
2011-12-10 10:41   ` Jeff King [this message]
2011-12-15 12:48     ` [PATCHv2 5/9] add generic terminal " Pete Wyckoff
2011-12-15 13:39       ` Jeff King
2011-12-15 21:59         ` Pete Wyckoff
2011-12-10 10:41   ` [PATCHv2 6/9] prompt: use git_terminal_prompt Jeff King
2011-12-10 10:41   ` [PATCHv2 7/9] credential: use git_prompt instead of git_getpass Jeff King
2011-12-10 10:41   ` [PATCHv2 8/9] Makefile: linux has /dev/tty Jeff King
2011-12-10 10:41   ` [PATCHv2 9/9] Makefile: OS X " Jeff King
2011-12-12 21:10     ` [PATCH 1/2] Makefile: Windows lacks /dev/tty Johannes Sixt
2011-12-12 21:12       ` [PATCH 2/2] Makefile: optionally exclude code that needs Unix sockets Johannes Sixt
2011-12-12 21:39         ` Jeff King
2011-12-12 23:31           ` Junio C Hamano
2011-12-13  0:58             ` Jeff King
2011-12-13  0:45           ` Junio C Hamano
2011-12-13 20:00             ` Johannes Sixt
2011-12-14  0:14               ` Junio C Hamano
2011-12-12 21:18       ` [PATCH 1/2] Makefile: Windows lacks /dev/tty Jeff King
2011-12-12 21:52         ` Johannes Sixt
2011-12-10 10:53 ` [PATCH 1/1] contrib: add credential helper for OS X Keychain Jeff King

Reply instructions:

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

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

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20111210104101.GE16648@sigill.intra.peff.net \
    --to=peff@peff.net \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).