Skip to content

Commit 1bfe99e

Browse files
committed
Merge branch 'ef/mingw-tty-getpass'
Update getpass() emulation for MinGW. * ef/mingw-tty-getpass: mingw: get rid of getpass implementation mingw: reuse tty-version of git_terminal_prompt compat/terminal: separate input and output handles compat/terminal: factor out echo-disabling mingw: make fgetc raise SIGINT if apropriate mingw: correct exit-code for SIGALRM's SIG_DFL
2 parents f993e2e + f7a4cea commit 1bfe99e

File tree

3 files changed

+169
-56
lines changed

3 files changed

+169
-56
lines changed

compat/mingw.c

Lines changed: 66 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,31 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
319319
return write(fd, buf, min(count, 31 * 1024 * 1024));
320320
}
321321

322+
static BOOL WINAPI ctrl_ignore(DWORD type)
323+
{
324+
return TRUE;
325+
}
326+
327+
#undef fgetc
328+
int mingw_fgetc(FILE *stream)
329+
{
330+
int ch;
331+
if (!isatty(_fileno(stream)))
332+
return fgetc(stream);
333+
334+
SetConsoleCtrlHandler(ctrl_ignore, TRUE);
335+
while (1) {
336+
ch = fgetc(stream);
337+
if (ch != EOF || GetLastError() != ERROR_OPERATION_ABORTED)
338+
break;
339+
340+
/* Ctrl+C was pressed, simulate SIGINT and retry */
341+
mingw_raise(SIGINT);
342+
}
343+
SetConsoleCtrlHandler(ctrl_ignore, FALSE);
344+
return ch;
345+
}
346+
322347
#undef fopen
323348
FILE *mingw_fopen (const char *filename, const char *otype)
324349
{
@@ -1546,7 +1571,7 @@ static HANDLE timer_event;
15461571
static HANDLE timer_thread;
15471572
static int timer_interval;
15481573
static int one_shot;
1549-
static sig_handler_t timer_fn = SIG_DFL;
1574+
static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL;
15501575

15511576
/* The timer works like this:
15521577
* The thread, ticktack(), is a trivial routine that most of the time
@@ -1560,10 +1585,7 @@ static sig_handler_t timer_fn = SIG_DFL;
15601585
static unsigned __stdcall ticktack(void *dummy)
15611586
{
15621587
while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
1563-
if (timer_fn == SIG_DFL)
1564-
die("Alarm");
1565-
if (timer_fn != SIG_IGN)
1566-
timer_fn(SIGALRM);
1588+
mingw_raise(SIGALRM);
15671589
if (one_shot)
15681590
break;
15691591
}
@@ -1654,12 +1676,49 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out)
16541676
sig_handler_t mingw_signal(int sig, sig_handler_t handler)
16551677
{
16561678
sig_handler_t old = timer_fn;
1657-
if (sig != SIGALRM)
1679+
1680+
switch (sig) {
1681+
case SIGALRM:
1682+
timer_fn = handler;
1683+
break;
1684+
1685+
case SIGINT:
1686+
sigint_fn = handler;
1687+
break;
1688+
1689+
default:
16581690
return signal(sig, handler);
1659-
timer_fn = handler;
1691+
}
1692+
16601693
return old;
16611694
}
16621695

1696+
#undef raise
1697+
int mingw_raise(int sig)
1698+
{
1699+
switch (sig) {
1700+
case SIGALRM:
1701+
if (timer_fn == SIG_DFL) {
1702+
if (isatty(STDERR_FILENO))
1703+
fputs("Alarm clock\n", stderr);
1704+
exit(128 + SIGALRM);
1705+
} else if (timer_fn != SIG_IGN)
1706+
timer_fn(SIGALRM);
1707+
return 0;
1708+
1709+
case SIGINT:
1710+
if (sigint_fn == SIG_DFL)
1711+
exit(128 + SIGINT);
1712+
else if (sigint_fn != SIG_IGN)
1713+
sigint_fn(SIGINT);
1714+
return 0;
1715+
1716+
default:
1717+
return raise(sig);
1718+
}
1719+
}
1720+
1721+
16631722
static const char *make_backslash_path(const char *path)
16641723
{
16651724
static char buf[PATH_MAX + 1];
@@ -1721,21 +1780,6 @@ int link(const char *oldpath, const char *newpath)
17211780
return 0;
17221781
}
17231782

1724-
char *getpass(const char *prompt)
1725-
{
1726-
struct strbuf buf = STRBUF_INIT;
1727-
1728-
fputs(prompt, stderr);
1729-
for (;;) {
1730-
char c = _getch();
1731-
if (c == '\r' || c == '\n')
1732-
break;
1733-
strbuf_addch(&buf, c);
1734-
}
1735-
fputs("\n", stderr);
1736-
return strbuf_detach(&buf, NULL);
1737-
}
1738-
17391783
pid_t waitpid(pid_t pid, int *status, int options)
17401784
{
17411785
HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,

compat/mingw.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ struct passwd {
5555
char *pw_dir;
5656
};
5757

58-
extern char *getpass(const char *prompt);
59-
6058
typedef void (__cdecl *sig_handler_t)(int);
6159
struct sigaction {
6260
sig_handler_t sa_handler;
@@ -179,6 +177,9 @@ int mingw_open (const char *filename, int oflags, ...);
179177
ssize_t mingw_write(int fd, const void *buf, size_t count);
180178
#define write mingw_write
181179

180+
int mingw_fgetc(FILE *stream);
181+
#define fgetc mingw_fgetc
182+
182183
FILE *mingw_fopen (const char *filename, const char *otype);
183184
#define fopen mingw_fopen
184185

@@ -290,6 +291,9 @@ static inline unsigned int git_ntohl(unsigned int x)
290291
sig_handler_t mingw_signal(int sig, sig_handler_t handler);
291292
#define signal mingw_signal
292293

294+
int mingw_raise(int sig);
295+
#define raise mingw_raise
296+
293297
/*
294298
* ANSI emulation wrappers
295299
*/

compat/terminal.c

Lines changed: 97 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,22 @@
33
#include "sigchain.h"
44
#include "strbuf.h"
55

6+
#if defined(HAVE_DEV_TTY) || defined(WIN32)
7+
8+
static void restore_term(void);
9+
10+
static void restore_term_on_signal(int sig)
11+
{
12+
restore_term();
13+
sigchain_pop(sig);
14+
raise(sig);
15+
}
16+
617
#ifdef HAVE_DEV_TTY
718

19+
#define INPUT_PATH "/dev/tty"
20+
#define OUTPUT_PATH "/dev/tty"
21+
822
static int term_fd = -1;
923
static struct termios old_term;
1024

@@ -14,58 +28,109 @@ static void restore_term(void)
1428
return;
1529

1630
tcsetattr(term_fd, TCSAFLUSH, &old_term);
31+
close(term_fd);
1732
term_fd = -1;
1833
}
1934

20-
static void restore_term_on_signal(int sig)
35+
static int disable_echo(void)
2136
{
22-
restore_term();
23-
sigchain_pop(sig);
24-
raise(sig);
37+
struct termios t;
38+
39+
term_fd = open("/dev/tty", O_RDWR);
40+
if (tcgetattr(term_fd, &t) < 0)
41+
goto error;
42+
43+
old_term = t;
44+
sigchain_push_common(restore_term_on_signal);
45+
46+
t.c_lflag &= ~ECHO;
47+
if (!tcsetattr(term_fd, TCSAFLUSH, &t))
48+
return 0;
49+
50+
error:
51+
close(term_fd);
52+
term_fd = -1;
53+
return -1;
54+
}
55+
56+
#elif defined(WIN32)
57+
58+
#define INPUT_PATH "CONIN$"
59+
#define OUTPUT_PATH "CONOUT$"
60+
#define FORCE_TEXT "t"
61+
62+
static HANDLE hconin = INVALID_HANDLE_VALUE;
63+
static DWORD cmode;
64+
65+
static void restore_term(void)
66+
{
67+
if (hconin == INVALID_HANDLE_VALUE)
68+
return;
69+
70+
SetConsoleMode(hconin, cmode);
71+
CloseHandle(hconin);
72+
hconin = INVALID_HANDLE_VALUE;
2573
}
2674

75+
static int disable_echo(void)
76+
{
77+
hconin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
78+
FILE_SHARE_READ, NULL, OPEN_EXISTING,
79+
FILE_ATTRIBUTE_NORMAL, NULL);
80+
if (hconin == INVALID_HANDLE_VALUE)
81+
return -1;
82+
83+
GetConsoleMode(hconin, &cmode);
84+
sigchain_push_common(restore_term_on_signal);
85+
if (!SetConsoleMode(hconin, cmode & (~ENABLE_ECHO_INPUT))) {
86+
CloseHandle(hconin);
87+
hconin = INVALID_HANDLE_VALUE;
88+
return -1;
89+
}
90+
91+
return 0;
92+
}
93+
94+
#endif
95+
96+
#ifndef FORCE_TEXT
97+
#define FORCE_TEXT
98+
#endif
99+
27100
char *git_terminal_prompt(const char *prompt, int echo)
28101
{
29102
static struct strbuf buf = STRBUF_INIT;
30103
int r;
31-
FILE *fh;
104+
FILE *input_fh, *output_fh;
32105

33-
fh = fopen("/dev/tty", "w+");
34-
if (!fh)
106+
input_fh = fopen(INPUT_PATH, "r" FORCE_TEXT);
107+
if (!input_fh)
35108
return NULL;
36109

37-
if (!echo) {
38-
struct termios t;
39-
40-
if (tcgetattr(fileno(fh), &t) < 0) {
41-
fclose(fh);
42-
return NULL;
43-
}
44-
45-
old_term = t;
46-
term_fd = fileno(fh);
47-
sigchain_push_common(restore_term_on_signal);
48-
49-
t.c_lflag &= ~ECHO;
50-
if (tcsetattr(fileno(fh), TCSAFLUSH, &t) < 0) {
51-
term_fd = -1;
52-
fclose(fh);
53-
return NULL;
54-
}
110+
output_fh = fopen(OUTPUT_PATH, "w" FORCE_TEXT);
111+
if (!output_fh) {
112+
fclose(input_fh);
113+
return NULL;
114+
}
115+
116+
if (!echo && disable_echo()) {
117+
fclose(input_fh);
118+
fclose(output_fh);
119+
return NULL;
55120
}
56121

57-
fputs(prompt, fh);
58-
fflush(fh);
122+
fputs(prompt, output_fh);
123+
fflush(output_fh);
59124

60-
r = strbuf_getline(&buf, fh, '\n');
125+
r = strbuf_getline(&buf, input_fh, '\n');
61126
if (!echo) {
62-
fseek(fh, SEEK_CUR, 0);
63-
putc('\n', fh);
64-
fflush(fh);
127+
putc('\n', output_fh);
128+
fflush(output_fh);
65129
}
66130

67131
restore_term();
68-
fclose(fh);
132+
fclose(input_fh);
133+
fclose(output_fh);
69134

70135
if (r == EOF)
71136
return NULL;

0 commit comments

Comments
 (0)