forked from xiaolai/git
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add generic terminal prompt function
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
- Loading branch information
Showing
3 changed files
with
96 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 */ |