From 7d45be2c08f4b7a9b745c64cb906210017474f43 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 d9d3945afa391f..703204755853cf 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 @@ static char *shell_prompt(const char *prompt, int echo) 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 55a5bfb936be5290f46ff54e82b712aebf32b453 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 703204755853cf..561d339f44c0b8 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 80a18d4bf59196de2d4f8e431ba5fc9cf1f01cdf 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 561d339f44c0b8..00eb4c51470831 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);