1- #include "git-compat-util .h"
1+ #include "cache .h"
22#include "compat/terminal.h"
33#include "sigchain.h"
44#include "strbuf.h"
@@ -24,6 +24,102 @@ static volatile sig_atomic_t term_fd_needs_closing;
2424static int term_fd = -1 ;
2525static struct termios old_term ;
2626
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+
27123static void close_term_fd (void )
28124{
29125 if (term_fd_needs_closing )
@@ -40,10 +136,13 @@ void restore_term(void)
40136 tcsetattr (term_fd , TCSAFLUSH , & old_term );
41137 close_term_fd ();
42138 sigchain_pop_common ();
139+ reset_job_signals ();
43140}
44141
45142int save_term (enum save_term_flags flags )
46143{
144+ struct sigaction sa ;
145+
47146 if (term_fd < 0 )
48147 term_fd = ((flags & SAVE_TERM_STDIN )
49148 ? 0
@@ -56,6 +155,26 @@ int save_term(enum save_term_flags flags)
56155 return -1 ;
57156 }
58157 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 );
59178
60179 return 0 ;
61180}
@@ -78,6 +197,7 @@ static int disable_bits(enum save_term_flags flags, tcflag_t bits)
78197 return 0 ;
79198
80199 sigchain_pop_common ();
200+ reset_job_signals ();
81201 close_term_fd ();
82202 return -1 ;
83203}
@@ -102,6 +222,7 @@ static int getchar_with_timeout(int timeout)
102222 fd_set readfds ;
103223 int res ;
104224
225+ again :
105226 if (timeout >= 0 ) {
106227 tv .tv_sec = timeout / 1000 ;
107228 tv .tv_usec = (timeout % 1000 ) * 1000 ;
@@ -111,9 +232,14 @@ static int getchar_with_timeout(int timeout)
111232 FD_ZERO (& readfds );
112233 FD_SET (0 , & readfds );
113234 res = select (1 , & readfds , NULL , NULL , tvp );
114- if (res <= 0 )
235+ if (! res )
115236 return EOF ;
116-
237+ if (res < 0 ) {
238+ if (errno == EINTR )
239+ goto again ;
240+ else
241+ return EOF ;
242+ }
117243 return getchar ();
118244}
119245
0 commit comments