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
This commit is contained in:
commit
1bfe99ed36
@ -319,6 +319,31 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
|
||||
return write(fd, buf, min(count, 31 * 1024 * 1024));
|
||||
}
|
||||
|
||||
static BOOL WINAPI ctrl_ignore(DWORD type)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef fgetc
|
||||
int mingw_fgetc(FILE *stream)
|
||||
{
|
||||
int ch;
|
||||
if (!isatty(_fileno(stream)))
|
||||
return fgetc(stream);
|
||||
|
||||
SetConsoleCtrlHandler(ctrl_ignore, TRUE);
|
||||
while (1) {
|
||||
ch = fgetc(stream);
|
||||
if (ch != EOF || GetLastError() != ERROR_OPERATION_ABORTED)
|
||||
break;
|
||||
|
||||
/* Ctrl+C was pressed, simulate SIGINT and retry */
|
||||
mingw_raise(SIGINT);
|
||||
}
|
||||
SetConsoleCtrlHandler(ctrl_ignore, FALSE);
|
||||
return ch;
|
||||
}
|
||||
|
||||
#undef fopen
|
||||
FILE *mingw_fopen (const char *filename, const char *otype)
|
||||
{
|
||||
@ -1546,7 +1571,7 @@ static HANDLE timer_event;
|
||||
static HANDLE timer_thread;
|
||||
static int timer_interval;
|
||||
static int one_shot;
|
||||
static sig_handler_t timer_fn = SIG_DFL;
|
||||
static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL;
|
||||
|
||||
/* The timer works like this:
|
||||
* The thread, ticktack(), is a trivial routine that most of the time
|
||||
@ -1560,10 +1585,7 @@ static sig_handler_t timer_fn = SIG_DFL;
|
||||
static unsigned __stdcall ticktack(void *dummy)
|
||||
{
|
||||
while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
|
||||
if (timer_fn == SIG_DFL)
|
||||
die("Alarm");
|
||||
if (timer_fn != SIG_IGN)
|
||||
timer_fn(SIGALRM);
|
||||
mingw_raise(SIGALRM);
|
||||
if (one_shot)
|
||||
break;
|
||||
}
|
||||
@ -1654,12 +1676,49 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out)
|
||||
sig_handler_t mingw_signal(int sig, sig_handler_t handler)
|
||||
{
|
||||
sig_handler_t old = timer_fn;
|
||||
if (sig != SIGALRM)
|
||||
|
||||
switch (sig) {
|
||||
case SIGALRM:
|
||||
timer_fn = handler;
|
||||
break;
|
||||
|
||||
case SIGINT:
|
||||
sigint_fn = handler;
|
||||
break;
|
||||
|
||||
default:
|
||||
return signal(sig, handler);
|
||||
timer_fn = handler;
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
#undef raise
|
||||
int mingw_raise(int sig)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGALRM:
|
||||
if (timer_fn == SIG_DFL) {
|
||||
if (isatty(STDERR_FILENO))
|
||||
fputs("Alarm clock\n", stderr);
|
||||
exit(128 + SIGALRM);
|
||||
} else if (timer_fn != SIG_IGN)
|
||||
timer_fn(SIGALRM);
|
||||
return 0;
|
||||
|
||||
case SIGINT:
|
||||
if (sigint_fn == SIG_DFL)
|
||||
exit(128 + SIGINT);
|
||||
else if (sigint_fn != SIG_IGN)
|
||||
sigint_fn(SIGINT);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return raise(sig);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char *make_backslash_path(const char *path)
|
||||
{
|
||||
static char buf[PATH_MAX + 1];
|
||||
@ -1721,21 +1780,6 @@ int link(const char *oldpath, const char *newpath)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *getpass(const char *prompt)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
|
||||
fputs(prompt, stderr);
|
||||
for (;;) {
|
||||
char c = _getch();
|
||||
if (c == '\r' || c == '\n')
|
||||
break;
|
||||
strbuf_addch(&buf, c);
|
||||
}
|
||||
fputs("\n", stderr);
|
||||
return strbuf_detach(&buf, NULL);
|
||||
}
|
||||
|
||||
pid_t waitpid(pid_t pid, int *status, int options)
|
||||
{
|
||||
HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
|
||||
|
@ -55,8 +55,6 @@ struct passwd {
|
||||
char *pw_dir;
|
||||
};
|
||||
|
||||
extern char *getpass(const char *prompt);
|
||||
|
||||
typedef void (__cdecl *sig_handler_t)(int);
|
||||
struct sigaction {
|
||||
sig_handler_t sa_handler;
|
||||
@ -179,6 +177,9 @@ int mingw_open (const char *filename, int oflags, ...);
|
||||
ssize_t mingw_write(int fd, const void *buf, size_t count);
|
||||
#define write mingw_write
|
||||
|
||||
int mingw_fgetc(FILE *stream);
|
||||
#define fgetc mingw_fgetc
|
||||
|
||||
FILE *mingw_fopen (const char *filename, const char *otype);
|
||||
#define fopen mingw_fopen
|
||||
|
||||
@ -290,6 +291,9 @@ static inline unsigned int git_ntohl(unsigned int x)
|
||||
sig_handler_t mingw_signal(int sig, sig_handler_t handler);
|
||||
#define signal mingw_signal
|
||||
|
||||
int mingw_raise(int sig);
|
||||
#define raise mingw_raise
|
||||
|
||||
/*
|
||||
* ANSI emulation wrappers
|
||||
*/
|
||||
|
@ -3,8 +3,22 @@
|
||||
#include "sigchain.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
#if defined(HAVE_DEV_TTY) || defined(WIN32)
|
||||
|
||||
static void restore_term(void);
|
||||
|
||||
static void restore_term_on_signal(int sig)
|
||||
{
|
||||
restore_term();
|
||||
sigchain_pop(sig);
|
||||
raise(sig);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DEV_TTY
|
||||
|
||||
#define INPUT_PATH "/dev/tty"
|
||||
#define OUTPUT_PATH "/dev/tty"
|
||||
|
||||
static int term_fd = -1;
|
||||
static struct termios old_term;
|
||||
|
||||
@ -14,58 +28,109 @@ static void restore_term(void)
|
||||
return;
|
||||
|
||||
tcsetattr(term_fd, TCSAFLUSH, &old_term);
|
||||
close(term_fd);
|
||||
term_fd = -1;
|
||||
}
|
||||
|
||||
static void restore_term_on_signal(int sig)
|
||||
static int disable_echo(void)
|
||||
{
|
||||
restore_term();
|
||||
sigchain_pop(sig);
|
||||
raise(sig);
|
||||
struct termios t;
|
||||
|
||||
term_fd = open("/dev/tty", O_RDWR);
|
||||
if (tcgetattr(term_fd, &t) < 0)
|
||||
goto error;
|
||||
|
||||
old_term = t;
|
||||
sigchain_push_common(restore_term_on_signal);
|
||||
|
||||
t.c_lflag &= ~ECHO;
|
||||
if (!tcsetattr(term_fd, TCSAFLUSH, &t))
|
||||
return 0;
|
||||
|
||||
error:
|
||||
close(term_fd);
|
||||
term_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#elif defined(WIN32)
|
||||
|
||||
#define INPUT_PATH "CONIN$"
|
||||
#define OUTPUT_PATH "CONOUT$"
|
||||
#define FORCE_TEXT "t"
|
||||
|
||||
static HANDLE hconin = INVALID_HANDLE_VALUE;
|
||||
static DWORD cmode;
|
||||
|
||||
static void restore_term(void)
|
||||
{
|
||||
if (hconin == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
|
||||
SetConsoleMode(hconin, cmode);
|
||||
CloseHandle(hconin);
|
||||
hconin = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
static int disable_echo(void)
|
||||
{
|
||||
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);
|
||||
sigchain_push_common(restore_term_on_signal);
|
||||
if (!SetConsoleMode(hconin, cmode & (~ENABLE_ECHO_INPUT))) {
|
||||
CloseHandle(hconin);
|
||||
hconin = INVALID_HANDLE_VALUE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef FORCE_TEXT
|
||||
#define FORCE_TEXT
|
||||
#endif
|
||||
|
||||
char *git_terminal_prompt(const char *prompt, int echo)
|
||||
{
|
||||
static struct strbuf buf = STRBUF_INIT;
|
||||
int r;
|
||||
FILE *fh;
|
||||
FILE *input_fh, *output_fh;
|
||||
|
||||
fh = fopen("/dev/tty", "w+");
|
||||
if (!fh)
|
||||
input_fh = fopen(INPUT_PATH, "r" FORCE_TEXT);
|
||||
if (!input_fh)
|
||||
return NULL;
|
||||
|
||||
if (!echo) {
|
||||
struct termios t;
|
||||
|
||||
if (tcgetattr(fileno(fh), &t) < 0) {
|
||||
fclose(fh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
old_term = t;
|
||||
term_fd = fileno(fh);
|
||||
sigchain_push_common(restore_term_on_signal);
|
||||
|
||||
t.c_lflag &= ~ECHO;
|
||||
if (tcsetattr(fileno(fh), TCSAFLUSH, &t) < 0) {
|
||||
term_fd = -1;
|
||||
fclose(fh);
|
||||
return NULL;
|
||||
}
|
||||
output_fh = fopen(OUTPUT_PATH, "w" FORCE_TEXT);
|
||||
if (!output_fh) {
|
||||
fclose(input_fh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fputs(prompt, fh);
|
||||
fflush(fh);
|
||||
if (!echo && disable_echo()) {
|
||||
fclose(input_fh);
|
||||
fclose(output_fh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = strbuf_getline(&buf, fh, '\n');
|
||||
fputs(prompt, output_fh);
|
||||
fflush(output_fh);
|
||||
|
||||
r = strbuf_getline(&buf, input_fh, '\n');
|
||||
if (!echo) {
|
||||
fseek(fh, SEEK_CUR, 0);
|
||||
putc('\n', fh);
|
||||
fflush(fh);
|
||||
putc('\n', output_fh);
|
||||
fflush(output_fh);
|
||||
}
|
||||
|
||||
restore_term();
|
||||
fclose(fh);
|
||||
fclose(input_fh);
|
||||
fclose(output_fh);
|
||||
|
||||
if (r == EOF)
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user