1- #include "git-compat-util .h"
1+ #include "cache .h"
22#include "compat/terminal.h"
33#include "sigchain.h"
44#include "strbuf.h"
@@ -20,39 +20,171 @@ static void restore_term_on_signal(int sig)
2020#define INPUT_PATH "/dev/tty"
2121#define OUTPUT_PATH "/dev/tty"
2222
23+ static volatile sig_atomic_t term_fd_needs_closing ;
2324static int term_fd = -1 ;
2425static struct termios old_term ;
2526
27+ static const char * background_resume_msg ;
28+ static const char * restore_error_msg ;
29+ static volatile sig_atomic_t ttou_received ;
30+
31+ /* async safe error function for use by signal handlers. */
32+ static void write_err (const char * msg )
33+ {
34+ write_in_full (2 , "error: " , strlen ("error: " ));
35+ write_in_full (2 , msg , strlen (msg ));
36+ write_in_full (2 , "\n" , 1 );
37+ }
38+
39+ static void print_background_resume_msg (int signo )
40+ {
41+ int saved_errno = errno ;
42+ sigset_t mask ;
43+ struct sigaction old_sa ;
44+ struct sigaction sa = { .sa_handler = SIG_DFL };
45+
46+ ttou_received = 1 ;
47+ write_err (background_resume_msg );
48+ sigaction (signo , & sa , & old_sa );
49+ raise (signo );
50+ sigemptyset (& mask );
51+ sigaddset (& mask , signo );
52+ sigprocmask (SIG_UNBLOCK , & mask , NULL );
53+ /* Stopped here */
54+ sigprocmask (SIG_BLOCK , & mask , NULL );
55+ sigaction (signo , & old_sa , NULL );
56+ errno = saved_errno ;
57+ }
58+
59+ static void restore_terminal_on_suspend (int signo )
60+ {
61+ int saved_errno = errno ;
62+ int res ;
63+ struct termios t ;
64+ sigset_t mask ;
65+ struct sigaction old_sa ;
66+ struct sigaction sa = { .sa_handler = SIG_DFL };
67+ int can_restore = 1 ;
68+
69+ if (tcgetattr (term_fd , & t ) < 0 )
70+ can_restore = 0 ;
71+
72+ if (tcsetattr (term_fd , TCSAFLUSH , & old_term ) < 0 )
73+ write_err (restore_error_msg );
74+
75+ sigaction (signo , & sa , & old_sa );
76+ raise (signo );
77+ sigemptyset (& mask );
78+ sigaddset (& mask , signo );
79+ sigprocmask (SIG_UNBLOCK , & mask , NULL );
80+ /* Stopped here */
81+ sigprocmask (SIG_BLOCK , & mask , NULL );
82+ sigaction (signo , & old_sa , NULL );
83+ if (!can_restore ) {
84+ write_err (restore_error_msg );
85+ goto out ;
86+ }
87+ /*
88+ * If we resume in the background then we receive SIGTTOU when calling
89+ * tcsetattr() below. Set up a handler to print an error message in that
90+ * case.
91+ */
92+ sigemptyset (& mask );
93+ sigaddset (& mask , SIGTTOU );
94+ sa .sa_mask = old_sa .sa_mask ;
95+ sa .sa_handler = print_background_resume_msg ;
96+ sa .sa_flags = SA_RESTART ;
97+ sigaction (SIGTTOU , & sa , & old_sa );
98+ again :
99+ ttou_received = 0 ;
100+ sigprocmask (SIG_UNBLOCK , & mask , NULL );
101+ res = tcsetattr (term_fd , TCSAFLUSH , & t );
102+ sigprocmask (SIG_BLOCK , & mask , NULL );
103+ if (ttou_received )
104+ goto again ;
105+ else if (res < 0 )
106+ write_err (restore_error_msg );
107+ sigaction (SIGTTOU , & old_sa , NULL );
108+ out :
109+ errno = saved_errno ;
110+ }
111+
112+ static void reset_job_signals (void )
113+ {
114+ if (restore_error_msg ) {
115+ signal (SIGTTIN , SIG_DFL );
116+ signal (SIGTTOU , SIG_DFL );
117+ signal (SIGTSTP , SIG_DFL );
118+ restore_error_msg = NULL ;
119+ background_resume_msg = NULL ;
120+ }
121+ }
122+
123+ static void close_term_fd (void )
124+ {
125+ if (term_fd_needs_closing )
126+ close (term_fd );
127+ term_fd_needs_closing = 0 ;
128+ term_fd = -1 ;
129+ }
130+
26131void restore_term (void )
27132{
28133 if (term_fd < 0 )
29134 return ;
30135
31136 tcsetattr (term_fd , TCSAFLUSH , & old_term );
32- close (term_fd );
33- term_fd = -1 ;
137+ close_term_fd ();
34138 sigchain_pop_common ();
139+ reset_job_signals ();
35140}
36141
37- int save_term (int full_duplex )
142+ int save_term (enum save_term_flags flags )
38143{
144+ struct sigaction sa ;
145+
39146 if (term_fd < 0 )
40- term_fd = open ("/dev/tty" , O_RDWR );
147+ term_fd = ((flags & SAVE_TERM_STDIN )
148+ ? 0
149+ : open ("/dev/tty" , O_RDWR ));
41150 if (term_fd < 0 )
42151 return -1 ;
43- if (tcgetattr (term_fd , & old_term ) < 0 )
152+ term_fd_needs_closing = !(flags & SAVE_TERM_STDIN );
153+ if (tcgetattr (term_fd , & old_term ) < 0 ) {
154+ close_term_fd ();
44155 return -1 ;
156+ }
45157 sigchain_push_common (restore_term_on_signal );
158+ /*
159+ * If job control is disabled then the shell will have set the
160+ * disposition of SIGTSTP to SIG_IGN.
161+ */
162+ sigaction (SIGTSTP , NULL , & sa );
163+ if (sa .sa_handler == SIG_IGN )
164+ return 0 ;
165+
166+ /* avoid calling gettext() from signal handler */
167+ background_resume_msg = _ ("cannot resume in the background, please use 'fg' to resume" );
168+ restore_error_msg = _ ("cannot restore terminal settings" );
169+ sa .sa_handler = restore_terminal_on_suspend ;
170+ sa .sa_flags = SA_RESTART ;
171+ sigemptyset (& sa .sa_mask );
172+ sigaddset (& sa .sa_mask , SIGTSTP );
173+ sigaddset (& sa .sa_mask , SIGTTIN );
174+ sigaddset (& sa .sa_mask , SIGTTOU );
175+ sigaction (SIGTSTP , & sa , NULL );
176+ sigaction (SIGTTIN , & sa , NULL );
177+ sigaction (SIGTTOU , & sa , NULL );
46178
47179 return 0 ;
48180}
49181
50- static int disable_bits (tcflag_t bits )
182+ static int disable_bits (enum save_term_flags flags , tcflag_t bits )
51183{
52184 struct termios t ;
53185
54- if (save_term (0 ) < 0 )
55- goto error ;
186+ if (save_term (flags ) < 0 )
187+ return -1 ;
56188
57189 t = old_term ;
58190
@@ -65,20 +197,50 @@ static int disable_bits(tcflag_t bits)
65197 return 0 ;
66198
67199 sigchain_pop_common ();
68- error :
69- close (term_fd );
70- term_fd = -1 ;
200+ reset_job_signals ();
201+ close_term_fd ();
71202 return -1 ;
72203}
73204
74- static int disable_echo (void )
205+ static int disable_echo (enum save_term_flags flags )
75206{
76- return disable_bits (ECHO );
207+ return disable_bits (flags , ECHO );
77208}
78209
79- static int enable_non_canonical (void )
210+ static int enable_non_canonical (enum save_term_flags flags )
80211{
81- return disable_bits (ICANON | ECHO );
212+ return disable_bits (flags , ICANON | ECHO );
213+ }
214+
215+ /*
216+ * On macos it is not possible to use poll() with a terminal so use select
217+ * instead.
218+ */
219+ static int getchar_with_timeout (int timeout )
220+ {
221+ struct timeval tv , * tvp = NULL ;
222+ fd_set readfds ;
223+ int res ;
224+
225+ again :
226+ if (timeout >= 0 ) {
227+ tv .tv_sec = timeout / 1000 ;
228+ tv .tv_usec = (timeout % 1000 ) * 1000 ;
229+ tvp = & tv ;
230+ }
231+
232+ FD_ZERO (& readfds );
233+ FD_SET (0 , & readfds );
234+ res = select (1 , & readfds , NULL , NULL , tvp );
235+ if (!res )
236+ return EOF ;
237+ if (res < 0 ) {
238+ if (errno == EINTR )
239+ goto again ;
240+ else
241+ return EOF ;
242+ }
243+ return getchar ();
82244}
83245
84246#elif defined(GIT_WINDOWS_NATIVE )
@@ -126,15 +288,15 @@ void restore_term(void)
126288 hconin = hconout = INVALID_HANDLE_VALUE ;
127289}
128290
129- int save_term (int full_duplex )
291+ int save_term (enum save_term_flags flags )
130292{
131293 hconin = CreateFileA ("CONIN$" , GENERIC_READ | GENERIC_WRITE ,
132294 FILE_SHARE_READ , NULL , OPEN_EXISTING ,
133295 FILE_ATTRIBUTE_NORMAL , NULL );
134296 if (hconin == INVALID_HANDLE_VALUE )
135297 return -1 ;
136298
137- if (full_duplex ) {
299+ if (flags & SAVE_TERM_DUPLEX ) {
138300 hconout = CreateFileA ("CONOUT$" , GENERIC_READ | GENERIC_WRITE ,
139301 FILE_SHARE_WRITE , NULL , OPEN_EXISTING ,
140302 FILE_ATTRIBUTE_NORMAL , NULL );
@@ -154,7 +316,7 @@ int save_term(int full_duplex)
154316 return -1 ;
155317}
156318
157- static int disable_bits (DWORD bits )
319+ static int disable_bits (enum save_term_flags flags , DWORD bits )
158320{
159321 if (use_stty ) {
160322 struct child_process cp = CHILD_PROCESS_INIT ;
@@ -191,7 +353,7 @@ static int disable_bits(DWORD bits)
191353 use_stty = 0 ;
192354 }
193355
194- if (save_term (0 ) < 0 )
356+ if (save_term (flags ) < 0 )
195357 return -1 ;
196358
197359 if (!SetConsoleMode (hconin , cmode_in & ~bits )) {
@@ -204,14 +366,15 @@ static int disable_bits(DWORD bits)
204366 return 0 ;
205367}
206368
207- static int disable_echo (void )
369+ static int disable_echo (enum save_term_flags flags )
208370{
209- return disable_bits (ENABLE_ECHO_INPUT );
371+ return disable_bits (flags , ENABLE_ECHO_INPUT );
210372}
211373
212- static int enable_non_canonical (void )
374+ static int enable_non_canonical (enum save_term_flags flags )
213375{
214- return disable_bits (ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT );
376+ return disable_bits (flags ,
377+ ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT );
215378}
216379
217380/*
@@ -245,6 +408,16 @@ static int mingw_getchar(void)
245408}
246409#define getchar mingw_getchar
247410
411+ static int getchar_with_timeout (int timeout )
412+ {
413+ struct pollfd pfd = { .fd = 0 , .events = POLLIN };
414+
415+ if (poll (& pfd , 1 , timeout ) < 1 )
416+ return EOF ;
417+
418+ return getchar ();
419+ }
420+
248421#endif
249422
250423#ifndef FORCE_TEXT
@@ -267,7 +440,7 @@ char *git_terminal_prompt(const char *prompt, int echo)
267440 return NULL ;
268441 }
269442
270- if (!echo && disable_echo ()) {
443+ if (!echo && disable_echo (0 )) {
271444 fclose (input_fh );
272445 fclose (output_fh );
273446 return NULL ;
@@ -361,7 +534,7 @@ int read_key_without_echo(struct strbuf *buf)
361534 static int warning_displayed ;
362535 int ch ;
363536
364- if (warning_displayed || enable_non_canonical () < 0 ) {
537+ if (warning_displayed || enable_non_canonical (SAVE_TERM_STDIN ) < 0 ) {
365538 if (!warning_displayed ) {
366539 warning ("reading single keystrokes not supported on "
367540 "this platform; reading line instead" );
@@ -395,12 +568,7 @@ int read_key_without_echo(struct strbuf *buf)
395568 * half a second when we know that the sequence is complete.
396569 */
397570 while (!is_known_escape_sequence (buf -> buf )) {
398- struct pollfd pfd = { .fd = 0 , .events = POLLIN };
399-
400- if (poll (& pfd , 1 , 500 ) < 1 )
401- break ;
402-
403- ch = getchar ();
571+ ch = getchar_with_timeout (500 );
404572 if (ch == EOF )
405573 break ;
406574 strbuf_addch (buf , ch );
@@ -413,10 +581,10 @@ int read_key_without_echo(struct strbuf *buf)
413581
414582#else
415583
416- int save_term (int full_duplex )
584+ int save_term (enum save_term_flags flags )
417585{
418- /* full_duplex == 1, but no support available */
419- return - full_duplex ;
586+ /* no duplex support available */
587+ return - !!( flags & SAVE_TERM_DUPLEX ) ;
420588}
421589
422590void restore_term (void )
0 commit comments