1#include "git-compat-util.h"
2#include "compat/terminal.h"
3#include "sigchain.h"
4#include "strbuf.h"
5
6#ifdef HAVE_DEV_TTY
7
8static int term_fd = -1;
9static struct termios old_term;
10
11static void restore_term(void)
12{
13 if (term_fd < 0)
14 return;
15
16 tcsetattr(term_fd, TCSAFLUSH, &old_term);
17 close(term_fd);
18 term_fd = -1;
19}
20
21static void restore_term_on_signal(int sig)
22{
23 restore_term();
24 sigchain_pop(sig);
25 raise(sig);
26}
27
28static int disable_echo(void)
29{
30 struct termios t;
31
32 term_fd = open("/dev/tty", O_RDWR);
33 if (tcgetattr(term_fd, &t) < 0)
34 goto error;
35
36 old_term = t;
37 sigchain_push_common(restore_term_on_signal);
38
39 t.c_lflag &= ~ECHO;
40 if (!tcsetattr(term_fd, TCSAFLUSH, &t))
41 return 0;
42
43error:
44 close(term_fd);
45 term_fd = -1;
46 return -1;
47}
48
49char *git_terminal_prompt(const char *prompt, int echo)
50{
51 static struct strbuf buf = STRBUF_INIT;
52 int r;
53 FILE *input_fh, *output_fh;
54
55 input_fh = fopen("/dev/tty", "r");
56 if (!input_fh)
57 return NULL;
58
59 output_fh = fopen("/dev/tty", "w");
60 if (!output_fh) {
61 fclose(input_fh);
62 return NULL;
63 }
64
65 if (!echo && disable_echo()) {
66 fclose(input_fh);
67 fclose(output_fh);
68 return NULL;
69 }
70
71 fputs(prompt, output_fh);
72 fflush(output_fh);
73
74 r = strbuf_getline(&buf, input_fh, '\n');
75 if (!echo) {
76 putc('\n', output_fh);
77 fflush(output_fh);
78 }
79
80 restore_term();
81 fclose(input_fh);
82 fclose(output_fh);
83
84 if (r == EOF)
85 return NULL;
86 return buf.buf;
87}
88
89#else
90
91char *git_terminal_prompt(const char *prompt, int echo)
92{
93 return getpass(prompt);
94}
95
96#endif