1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
#include "git-compat-util.h"
#include "compat/terminal.h"
#include "sigchain.h"
#include "strbuf.h"
#if defined(HAVE_DEV_TTY) || defined(GIT_WINDOWS_NATIVE)
static void restore_term(void);
static void restore_term_on_signal(int sig)
{
restore_term();
sigchain_pop(sig);
raise(sig);
}
#ifdef HAVE_DEV_TTY
#define INPUT_PATH "/dev/tty"
#define OUTPUT_PATH "/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);
close(term_fd);
term_fd = -1;
}
static int disable_echo(void)
{
struct termios t;
term_fd = open("/dev/tty", O_RDWR);
if (tcgetattr(term_fd, &t) < 0)
goto error;
old_term = t;
sigchain_push_common(restore_term_on_signal);
t.c_lflag &= ~ECHO;
if (!tcsetattr(term_fd, TCSAFLUSH, &t))
return 0;
error:
close(term_fd);
term_fd = -1;
return -1;
}
#elif defined(GIT_WINDOWS_NATIVE)
#define INPUT_PATH "CONIN$"
#define OUTPUT_PATH "CONOUT$"
#define FORCE_TEXT "t"
static HANDLE hconin = INVALID_HANDLE_VALUE;
static DWORD cmode;
static void restore_term(void)
{
if (hconin == INVALID_HANDLE_VALUE)
return;
SetConsoleMode(hconin, cmode);
CloseHandle(hconin);
hconin = INVALID_HANDLE_VALUE;
}
static int disable_echo(void)
{
hconin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hconin == INVALID_HANDLE_VALUE)
return -1;
GetConsoleMode(hconin, &cmode);
sigchain_push_common(restore_term_on_signal);
if (!SetConsoleMode(hconin, cmode & (~ENABLE_ECHO_INPUT))) {
CloseHandle(hconin);
hconin = INVALID_HANDLE_VALUE;
return -1;
}
return 0;
}
#endif
#ifndef FORCE_TEXT
#define FORCE_TEXT
#endif
char *git_terminal_prompt(const char *prompt, int echo)
{
static struct strbuf buf = STRBUF_INIT;
int r;
FILE *input_fh, *output_fh;
input_fh = fopen(INPUT_PATH, "r" FORCE_TEXT);
if (!input_fh)
return NULL;
output_fh = fopen(OUTPUT_PATH, "w" FORCE_TEXT);
if (!output_fh) {
fclose(input_fh);
return NULL;
}
if (!echo && disable_echo()) {
fclose(input_fh);
fclose(output_fh);
return NULL;
}
fputs(prompt, output_fh);
fflush(output_fh);
r = strbuf_getline(&buf, input_fh, '\n');
if (!echo) {
putc('\n', output_fh);
fflush(output_fh);
}
restore_term();
fclose(input_fh);
fclose(output_fh);
if (r == EOF)
return NULL;
return buf.buf;
}
#else
char *git_terminal_prompt(const char *prompt, int echo)
{
return getpass(prompt);
}
#endif
|