From 587912d8d4639270107dfaf1f06720a21a110457 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Feb 2018 02:50:03 +0100 Subject: [PATCH 1/3] mingw (git_terminal_prompt): work around BusyBox & WSL issues When trying to query the user directly via /dev/tty, both WSL's bash and BusyBox' bash emulation seem to have problems printing the value that they just read. The bash just stops in those instances, does not even execute any commands after the echo command. Let's just work around this by running the Bash snippet only in MSYS2's Bash: its `SHELL` variable has the `.exe` suffix, and neither WSL's nor BusyBox' bash set the `SHELL` variable to a path with that suffix. In the latter case, we simply exit with code 127 (indicating that the command was not found) and fall back to the CONIN$/CONOUT$ method quietly. Signed-off-by: Johannes Schindelin --- compat/terminal.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compat/terminal.c b/compat/terminal.c index d9d3945afa..7032047558 100644 --- a/compat/terminal.c +++ b/compat/terminal.c @@ -101,8 +101,10 @@ static char *shell_prompt(const char *prompt, int echo) const char *read_input[] = { /* Note: call 'bash' explicitly, as 'read -s' is bash-specific */ "bash", "-c", echo ? - "cat >/dev/tty && read -r line /dev/tty && read -r -s line /dev/tty", + "test \"a$SHELL\" != \"a${SHELL%.exe}\" || exit 127; cat >/dev/tty &&" + " read -r line /dev/tty &&" + " read -r -s line /dev/tty", NULL }; struct child_process child = CHILD_PROCESS_INIT; @@ -138,7 +140,10 @@ ret: close(child.out); code = finish_command(&child); if (code) { - error("failed to execute prompt script (exit code %d)", code); + if (code != 127) + error("failed to execute prompt script (exit code %d)", + code); + return NULL; } From f36a43d8bd916b4cafa3c790fb230022ed88c4e2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Feb 2018 02:50:03 +0100 Subject: [PATCH 2/3] mingw (git_terminal_prompt): do fall back to CONIN$/CONOUT$ method To support Git Bash running in a MinTTY, we use a dirty trick to access the MSYS2 pseudo terminal: we execute a Bash snippet that accesses /dev/tty. The idea was to fall back to writing to/reading from CONOUT$/CONIN$ if that Bash call failed because Bash was not found. However, we should fall back even in other error conditions, because we have not successfully read the user input. Let's make it so. Signed-off-by: Johannes Schindelin --- compat/terminal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/terminal.c b/compat/terminal.c index 7032047558..561d339f44 100644 --- a/compat/terminal.c +++ b/compat/terminal.c @@ -166,7 +166,7 @@ char *git_terminal_prompt(const char *prompt, int echo) /* try shell_prompt first, fall back to CONIN/OUT if bash is missing */ char *result = shell_prompt(prompt, echo); - if (result || errno != ENOENT) + if (result) return result; #endif From 0ef403a7a362ec2a974df28a3636108914aa04c0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Feb 2018 02:50:03 +0100 Subject: [PATCH 3/3] mingw (git_terminal_prompt): turn on echo explictly It turns out that when running in a Powershell window, we need to turn on ENABLE_ECHO_INPUT because the default would be *not* to echo anything. This also ensures that we use the input mode where all input is read until the user hits the Return key. Signed-off-by: Johannes Schindelin --- compat/terminal.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/compat/terminal.c b/compat/terminal.c index 561d339f44..00eb4c5147 100644 --- a/compat/terminal.c +++ b/compat/terminal.c @@ -77,17 +77,26 @@ static void restore_term(void) hconin = INVALID_HANDLE_VALUE; } -static int disable_echo(void) +static int set_echo(int echo) { - hconin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); + DWORD new_cmode; + + if (hconin == INVALID_HANDLE_VALUE) + 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); + new_cmode = cmode | ENABLE_LINE_INPUT; + if (echo) + new_cmode |= ENABLE_ECHO_INPUT; + else + new_cmode &= ~ENABLE_ECHO_INPUT; + sigchain_push_common(restore_term_on_signal); - if (!SetConsoleMode(hconin, cmode & (~ENABLE_ECHO_INPUT))) { + if (!SetConsoleMode(hconin, new_cmode)) { CloseHandle(hconin); hconin = INVALID_HANDLE_VALUE; return -1; @@ -96,6 +105,11 @@ static int disable_echo(void) return 0; } +static int disable_echo(void) +{ + return set_echo(0); +} + static char *shell_prompt(const char *prompt, int echo) { const char *read_input[] = { @@ -169,6 +183,8 @@ char *git_terminal_prompt(const char *prompt, int echo) if (result) return result; + if (echo && set_echo(1)) + return NULL; #endif input_fh = fopen(INPUT_PATH, "r" FORCE_TEXT);