]> git.ipfire.org Git - thirdparty/git.git/commitdiff
terminal: teach git how to save/restore its terminal settings
authorCarlo Marcelo Arenas Belón <carenas@gmail.com>
Tue, 5 Oct 2021 07:46:47 +0000 (00:46 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 6 Oct 2021 15:53:00 +0000 (08:53 -0700)
Currently, git will share its console with all its children (unless
they create their own), and is therefore possible that any of them
that might change the settings for it could affect its operations once
completed.

Refactor the platform specific functionality to save the terminal
settings and expand it to also do so for the output handler.

This will allow for the state of the terminal to be saved and
restored around a child that might misbehave (ex vi) which will
be implemented next.

Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
compat/terminal.c
compat/terminal.h

index 43b73ddc75891a090d81b5e4ef34864f83c653a8..5b903e7c7e3e32c25e59efcc151217d00d243d65 100644 (file)
@@ -8,8 +8,6 @@
 
 #if defined(HAVE_DEV_TTY) || defined(GIT_WINDOWS_NATIVE)
 
-static void restore_term(void);
-
 static void restore_term_on_signal(int sig)
 {
        restore_term();
@@ -25,7 +23,7 @@ static void restore_term_on_signal(int sig)
 static int term_fd = -1;
 static struct termios old_term;
 
-static void restore_term(void)
+void restore_term(void)
 {
        if (term_fd < 0)
                return;
@@ -35,15 +33,22 @@ static void restore_term(void)
        term_fd = -1;
 }
 
+int save_term(int full_duplex)
+{
+       if (term_fd < 0)
+               term_fd = open("/dev/tty", O_RDWR);
+
+       return (term_fd < 0) ? -1 : tcgetattr(term_fd, &old_term);
+}
+
 static int disable_bits(tcflag_t bits)
 {
        struct termios t;
 
-       term_fd = open("/dev/tty", O_RDWR);
-       if (tcgetattr(term_fd, &t) < 0)
+       if (save_term(0) < 0)
                goto error;
 
-       old_term = t;
+       t = old_term;
        sigchain_push_common(restore_term_on_signal);
 
        t.c_lflag &= ~bits;
@@ -75,9 +80,10 @@ static int enable_non_canonical(void)
 static int use_stty = 1;
 static struct string_list stty_restore = STRING_LIST_INIT_DUP;
 static HANDLE hconin = INVALID_HANDLE_VALUE;
-static DWORD cmode;
+static HANDLE hconout = INVALID_HANDLE_VALUE;
+static DWORD cmode_in, cmode_out;
 
-static void restore_term(void)
+void restore_term(void)
 {
        if (use_stty) {
                int i;
@@ -97,9 +103,42 @@ static void restore_term(void)
        if (hconin == INVALID_HANDLE_VALUE)
                return;
 
-       SetConsoleMode(hconin, cmode);
+       SetConsoleMode(hconin, cmode_in);
+       CloseHandle(hconin);
+       if (cmode_out) {
+               assert(hconout != INVALID_HANDLE_VALUE);
+               SetConsoleMode(hconout, cmode_out);
+               CloseHandle(hconout);
+       }
+
+       hconin = hconout = INVALID_HANDLE_VALUE;
+}
+
+int save_term(int full_duplex)
+{
+       hconin = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE,
+           FILE_SHARE_READ, NULL, OPEN_EXISTING,
+           FILE_ATTRIBUTE_NORMAL, NULL);
+       if (hconin == INVALID_HANDLE_VALUE)
+               return -1;
+
+       if (full_duplex) {
+               hconout = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE,
+                       FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+                       FILE_ATTRIBUTE_NORMAL, NULL);
+               if (hconout == INVALID_HANDLE_VALUE)
+                       goto error;
+
+               GetConsoleMode(hconout, &cmode_out);
+       }
+
+       GetConsoleMode(hconin, &cmode_in);
+       use_stty = 0;
+       return 0;
+error:
        CloseHandle(hconin);
        hconin = INVALID_HANDLE_VALUE;
+       return -1;
 }
 
 static int disable_bits(DWORD bits)
@@ -135,15 +174,11 @@ static int disable_bits(DWORD bits)
                use_stty = 0;
        }
 
-       hconin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
-           FILE_SHARE_READ, NULL, OPEN_EXISTING,
-           FILE_ATTRIBUTE_NORMAL, NULL);
-       if (hconin == INVALID_HANDLE_VALUE)
+       if (save_term(0) < 0)
                return -1;
 
-       GetConsoleMode(hconin, &cmode);
        sigchain_push_common(restore_term_on_signal);
-       if (!SetConsoleMode(hconin, cmode & ~bits)) {
+       if (!SetConsoleMode(hconin, cmode_in & ~bits)) {
                CloseHandle(hconin);
                hconin = INVALID_HANDLE_VALUE;
                return -1;
@@ -361,6 +396,16 @@ int read_key_without_echo(struct strbuf *buf)
 
 #else
 
+int save_term(int full_duplex)
+{
+       /* full_duplex == 1, but no support available */
+       return -full_duplex;
+}
+
+void restore_term(void)
+{
+}
+
 char *git_terminal_prompt(const char *prompt, int echo)
 {
        return getpass(prompt);
index a9d52b8464e2f6e3c39bc107078cb5b2a36aa5d5..e1770c575b2c5c501d3fbf3bcbe3873d288a1c92 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef COMPAT_TERMINAL_H
 #define COMPAT_TERMINAL_H
 
+int save_term(int full_duplex);
+void restore_term(void);
+
 char *git_terminal_prompt(const char *prompt, int echo);
 
 /* Read a single keystroke, without echoing it to the terminal */