Skip to content

Commit

Permalink
terminal: teach git how to save/restore the console
Browse files Browse the repository at this point in the history
Add two functions to push/pop the terminal state as needed, and
refactor the current users around it.

This will be used in a future patch to protect git from a cooked
console because of a broken child process.

Signed-off-by: Carlo Marcelo Arenas Belón <[email protected]>
  • Loading branch information
carenas committed Sep 30, 2021
1 parent 225bc32 commit d60439f
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 13 deletions.
72 changes: 59 additions & 13 deletions compat/terminal.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,38 @@ static void restore_term_on_signal(int sig)
static int term_fd = -1;
static struct termios old_term;

static void restore_term(void)
void pop_term(void)
{
if (term_fd < 0)
return;

tcsetattr(term_fd, TCSAFLUSH, &old_term);
}

static void restore_term(void)
{
pop_term();

close(term_fd);
term_fd = -1;
}

int push_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 (push_term(0) < 0)
goto error;

old_term = t;
t = old_term;
sigchain_push_common(restore_term_on_signal);

t.c_lflag &= ~bits;
Expand Down Expand Up @@ -75,7 +88,22 @@ 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 cmodein, cmodeout;

void pop_term(void)
{
if (hconin == INVALID_HANDLE_VALUE)
return;

SetConsoleMode(hconin, cmodein);
CloseHandle(hconin);
if (cmodeout) {
assert(hconout != INVALID_HANDLE_VALUE);
SetConsoleMode(hconout, cmodeout);
CloseHandle(hconout);
}
}

static void restore_term(void)
{
Expand All @@ -94,12 +122,34 @@ static void restore_term(void)
return;
}

pop_term();
hconin = hconout = INVALID_HANDLE_VALUE;
}

int push_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;
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;

SetConsoleMode(hconin, cmode);
GetConsoleMode(hconout, &cmodeout);
}

GetConsoleMode(hconin, &cmodein);
return 0;
error:
CloseHandle(hconin);
hconin = INVALID_HANDLE_VALUE;
return -1;
}

static int disable_bits(DWORD bits)
Expand Down Expand Up @@ -135,15 +185,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 (push_term(0) < 0)
return -1;

GetConsoleMode(hconin, &cmode);
sigchain_push_common(restore_term_on_signal);
if (!SetConsoleMode(hconin, cmode & ~bits)) {
if (!SetConsoleMode(hconin, cmodein & ~bits)) {
CloseHandle(hconin);
hconin = INVALID_HANDLE_VALUE;
return -1;
Expand Down
3 changes: 3 additions & 0 deletions compat/terminal.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#ifndef COMPAT_TERMINAL_H
#define COMPAT_TERMINAL_H

int push_term(int full_duplex);
void pop_term(void);

char *git_terminal_prompt(const char *prompt, int echo);

/* Read a single keystroke, without echoing it to the terminal */
Expand Down

0 comments on commit d60439f

Please sign in to comment.