1
- #include "git-compat-util .h"
1
+ #include "cache .h"
2
2
#include "compat/terminal.h"
3
3
#include "sigchain.h"
4
4
#include "strbuf.h"
@@ -20,39 +20,171 @@ static void restore_term_on_signal(int sig)
20
20
#define INPUT_PATH "/dev/tty"
21
21
#define OUTPUT_PATH "/dev/tty"
22
22
23
+ static volatile sig_atomic_t term_fd_needs_closing ;
23
24
static int term_fd = -1 ;
24
25
static struct termios old_term ;
25
26
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
+
26
131
void restore_term (void )
27
132
{
28
133
if (term_fd < 0 )
29
134
return ;
30
135
31
136
tcsetattr (term_fd , TCSAFLUSH , & old_term );
32
- close (term_fd );
33
- term_fd = -1 ;
137
+ close_term_fd ();
34
138
sigchain_pop_common ();
139
+ reset_job_signals ();
35
140
}
36
141
37
- int save_term (int full_duplex )
142
+ int save_term (enum save_term_flags flags )
38
143
{
144
+ struct sigaction sa ;
145
+
39
146
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 ));
41
150
if (term_fd < 0 )
42
151
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 ();
44
155
return -1 ;
156
+ }
45
157
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 );
46
178
47
179
return 0 ;
48
180
}
49
181
50
- static int disable_bits (tcflag_t bits )
182
+ static int disable_bits (enum save_term_flags flags , tcflag_t bits )
51
183
{
52
184
struct termios t ;
53
185
54
- if (save_term (0 ) < 0 )
55
- goto error ;
186
+ if (save_term (flags ) < 0 )
187
+ return -1 ;
56
188
57
189
t = old_term ;
58
190
@@ -65,20 +197,50 @@ static int disable_bits(tcflag_t bits)
65
197
return 0 ;
66
198
67
199
sigchain_pop_common ();
68
- error :
69
- close (term_fd );
70
- term_fd = -1 ;
200
+ reset_job_signals ();
201
+ close_term_fd ();
71
202
return -1 ;
72
203
}
73
204
74
- static int disable_echo (void )
205
+ static int disable_echo (enum save_term_flags flags )
75
206
{
76
- return disable_bits (ECHO );
207
+ return disable_bits (flags , ECHO );
77
208
}
78
209
79
- static int enable_non_canonical (void )
210
+ static int enable_non_canonical (enum save_term_flags flags )
80
211
{
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 ();
82
244
}
83
245
84
246
#elif defined(GIT_WINDOWS_NATIVE )
@@ -126,15 +288,15 @@ void restore_term(void)
126
288
hconin = hconout = INVALID_HANDLE_VALUE ;
127
289
}
128
290
129
- int save_term (int full_duplex )
291
+ int save_term (enum save_term_flags flags )
130
292
{
131
293
hconin = CreateFileA ("CONIN$" , GENERIC_READ | GENERIC_WRITE ,
132
294
FILE_SHARE_READ , NULL , OPEN_EXISTING ,
133
295
FILE_ATTRIBUTE_NORMAL , NULL );
134
296
if (hconin == INVALID_HANDLE_VALUE )
135
297
return -1 ;
136
298
137
- if (full_duplex ) {
299
+ if (flags & SAVE_TERM_DUPLEX ) {
138
300
hconout = CreateFileA ("CONOUT$" , GENERIC_READ | GENERIC_WRITE ,
139
301
FILE_SHARE_WRITE , NULL , OPEN_EXISTING ,
140
302
FILE_ATTRIBUTE_NORMAL , NULL );
@@ -154,7 +316,7 @@ int save_term(int full_duplex)
154
316
return -1 ;
155
317
}
156
318
157
- static int disable_bits (DWORD bits )
319
+ static int disable_bits (enum save_term_flags flags , DWORD bits )
158
320
{
159
321
if (use_stty ) {
160
322
struct child_process cp = CHILD_PROCESS_INIT ;
@@ -191,7 +353,7 @@ static int disable_bits(DWORD bits)
191
353
use_stty = 0 ;
192
354
}
193
355
194
- if (save_term (0 ) < 0 )
356
+ if (save_term (flags ) < 0 )
195
357
return -1 ;
196
358
197
359
if (!SetConsoleMode (hconin , cmode_in & ~bits )) {
@@ -204,14 +366,15 @@ static int disable_bits(DWORD bits)
204
366
return 0 ;
205
367
}
206
368
207
- static int disable_echo (void )
369
+ static int disable_echo (enum save_term_flags flags )
208
370
{
209
- return disable_bits (ENABLE_ECHO_INPUT );
371
+ return disable_bits (flags , ENABLE_ECHO_INPUT );
210
372
}
211
373
212
- static int enable_non_canonical (void )
374
+ static int enable_non_canonical (enum save_term_flags flags )
213
375
{
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 );
215
378
}
216
379
217
380
/*
@@ -245,6 +408,16 @@ static int mingw_getchar(void)
245
408
}
246
409
#define getchar mingw_getchar
247
410
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
+
248
421
#endif
249
422
250
423
#ifndef FORCE_TEXT
@@ -267,7 +440,7 @@ char *git_terminal_prompt(const char *prompt, int echo)
267
440
return NULL ;
268
441
}
269
442
270
- if (!echo && disable_echo ()) {
443
+ if (!echo && disable_echo (0 )) {
271
444
fclose (input_fh );
272
445
fclose (output_fh );
273
446
return NULL ;
@@ -361,7 +534,7 @@ int read_key_without_echo(struct strbuf *buf)
361
534
static int warning_displayed ;
362
535
int ch ;
363
536
364
- if (warning_displayed || enable_non_canonical () < 0 ) {
537
+ if (warning_displayed || enable_non_canonical (SAVE_TERM_STDIN ) < 0 ) {
365
538
if (!warning_displayed ) {
366
539
warning ("reading single keystrokes not supported on "
367
540
"this platform; reading line instead" );
@@ -395,12 +568,7 @@ int read_key_without_echo(struct strbuf *buf)
395
568
* half a second when we know that the sequence is complete.
396
569
*/
397
570
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 );
404
572
if (ch == EOF )
405
573
break ;
406
574
strbuf_addch (buf , ch );
@@ -413,10 +581,10 @@ int read_key_without_echo(struct strbuf *buf)
413
581
414
582
#else
415
583
416
- int save_term (int full_duplex )
584
+ int save_term (enum save_term_flags flags )
417
585
{
418
- /* full_duplex == 1, but no support available */
419
- return - full_duplex ;
586
+ /* no duplex support available */
587
+ return - !!( flags & SAVE_TERM_DUPLEX ) ;
420
588
}
421
589
422
590
void restore_term (void )
0 commit comments