| #include "git-compat-util.h" | |
| #include "compat/terminal.h" | |
| #include "sigchain.h" | |
| #include "strbuf.h" | |
| #if defined(HAVE_DEV_TTY) || defined(GIT_WINDOWS_NATIVE) | |
| 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; | |
| static void restore_term(void) | |
| { | |
| if (term_fd < 0) | |
| return; | |
| tcsetattr(term_fd, TCSAFLUSH, &old_term); | |
| close(term_fd); | |
| term_fd = -1; | |
| } | |
| static int disable_echo(void) | |
| { | |
| 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(GIT_WINDOWS_NATIVE) | |
| #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 *input_fh, *output_fh; | |
| input_fh = fopen(INPUT_PATH, "r" FORCE_TEXT); | |
| if (!input_fh) | |
| return NULL; | |
| output_fh = fopen(OUTPUT_PATH, "w" FORCE_TEXT); | |
| if (!output_fh) { | |
| fclose(input_fh); | |
| return NULL; | |
| } | |
| if (!echo && disable_echo()) { | |
| fclose(input_fh); | |
| fclose(output_fh); | |
| return NULL; | |
| } | |
| fputs(prompt, output_fh); | |
| fflush(output_fh); | |
| r = strbuf_getline_lf(&buf, input_fh); | |
| if (!echo) { | |
| putc('\n', output_fh); | |
| fflush(output_fh); | |
| } | |
| restore_term(); | |
| fclose(input_fh); | |
| fclose(output_fh); | |
| if (r == EOF) | |
| return NULL; | |
| return buf.buf; | |
| } | |
| #else | |
| char *git_terminal_prompt(const char *prompt, int echo) | |
| { | |
| return getpass(prompt); | |
| } | |
| #endif |