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"
@@ -24,6 +24,102 @@ static volatile sig_atomic_t term_fd_needs_closing;
24
24
static int term_fd = -1 ;
25
25
static struct termios old_term ;
26
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
+
27
123
static void close_term_fd (void )
28
124
{
29
125
if (term_fd_needs_closing )
@@ -40,10 +136,13 @@ void restore_term(void)
40
136
tcsetattr (term_fd , TCSAFLUSH , & old_term );
41
137
close_term_fd ();
42
138
sigchain_pop_common ();
139
+ reset_job_signals ();
43
140
}
44
141
45
142
int save_term (enum save_term_flags flags )
46
143
{
144
+ struct sigaction sa ;
145
+
47
146
if (term_fd < 0 )
48
147
term_fd = ((flags & SAVE_TERM_STDIN )
49
148
? 0
@@ -56,6 +155,26 @@ int save_term(enum save_term_flags flags)
56
155
return -1 ;
57
156
}
58
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 );
59
178
60
179
return 0 ;
61
180
}
@@ -78,6 +197,7 @@ static int disable_bits(enum save_term_flags flags, tcflag_t bits)
78
197
return 0 ;
79
198
80
199
sigchain_pop_common ();
200
+ reset_job_signals ();
81
201
close_term_fd ();
82
202
return -1 ;
83
203
}
@@ -102,6 +222,7 @@ static int getchar_with_timeout(int timeout)
102
222
fd_set readfds ;
103
223
int res ;
104
224
225
+ again :
105
226
if (timeout >= 0 ) {
106
227
tv .tv_sec = timeout / 1000 ;
107
228
tv .tv_usec = (timeout % 1000 ) * 1000 ;
@@ -111,9 +232,14 @@ static int getchar_with_timeout(int timeout)
111
232
FD_ZERO (& readfds );
112
233
FD_SET (0 , & readfds );
113
234
res = select (1 , & readfds , NULL , NULL , tvp );
114
- if (res <= 0 )
235
+ if (! res )
115
236
return EOF ;
116
-
237
+ if (res < 0 ) {
238
+ if (errno == EINTR )
239
+ goto again ;
240
+ else
241
+ return EOF ;
242
+ }
117
243
return getchar ();
118
244
}
119
245
0 commit comments