havelib: Fix for Solaris 11 OpenIndiana and Solaris 11 OmniOS.
[gnulib.git] / lib / term-style-control.c
blob78372b4de8ac8354be12d67c2096b0bf5d773d1f
1 /* Terminal control for outputting styled text to a terminal.
2 Copyright (C) 2006-2008, 2017, 2019-2020 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2019.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 #include <config.h>
20 /* Specification. */
21 #include "term-style-control.h"
23 /* Set to 1 to get debugging output regarding signals. */
24 #define DEBUG_SIGNALS 0
26 #include <errno.h>
27 #include <signal.h>
28 #include <stdbool.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #if DEBUG_SIGNALS
33 # include <stdio.h>
34 #endif
35 #if HAVE_TCGETATTR
36 # include <termios.h>
37 # if !defined NOFLSH /* QNX */
38 # define NOFLSH 0
39 # endif
40 #endif
41 #if HAVE_TCGETATTR
42 # include <sys/stat.h>
43 #endif
45 #include "fatal-signal.h"
46 #include "sig-handler.h"
47 #include "full-write.h"
48 #include "same-inode.h"
50 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
53 /* ============================ EINTR handling ============================ */
55 /* EINTR handling for tcgetattr(), tcsetattr().
56 These functions can return -1/EINTR even when we don't have any
57 signal handlers set up, namely when we get interrupted via SIGSTOP. */
59 #if HAVE_TCGETATTR
61 static inline int
62 nonintr_tcgetattr (int fd, struct termios *tcp)
64 int retval;
67 retval = tcgetattr (fd, tcp);
68 while (retval < 0 && errno == EINTR);
70 return retval;
73 static inline int
74 nonintr_tcsetattr (int fd, int flush_mode, const struct termios *tcp)
76 int retval;
79 retval = tcsetattr (fd, flush_mode, tcp);
80 while (retval < 0 && errno == EINTR);
82 return retval;
85 #endif
88 /* ========================== Logging primitives ========================== */
90 /* We need logging, especially for the signal handling, because
91 - Debugging through gdb is hardly possible, because gdb produces output
92 by itself and interferes with the process states.
93 - strace is buggy when it comes to SIGTSTP handling: By default, it
94 sends the process a SIGSTOP signal instead of SIGTSTP. It supports
95 an option '-D -I4' to mitigate this, though. Also, race conditions
96 appear with different probability with and without strace.
97 fprintf(stderr) is not possible within async-safe code, because fprintf()
98 may invoke malloc(). */
100 #if DEBUG_SIGNALS
102 /* Log a simple message. */
103 static _GL_ASYNC_SAFE void
104 log_message (const char *message)
106 full_write (STDERR_FILENO, message, strlen (message));
109 #else
111 # define log_message(message)
113 #endif
115 #if HAVE_TCGETATTR || DEBUG_SIGNALS
117 /* Async-safe implementation of sprintf (str, "%d", n). */
118 static _GL_ASYNC_SAFE void
119 sprintf_integer (char *str, int x)
121 unsigned int y;
122 char buf[20];
123 char *p;
124 size_t n;
126 if (x < 0)
128 *str++ = '-';
129 y = (unsigned int) (-1 - x) + 1;
131 else
132 y = x;
134 p = buf + sizeof (buf);
137 *--p = '0' + (y % 10);
138 y = y / 10;
140 while (y > 0);
141 n = buf + sizeof (buf) - p;
142 memcpy (str, p, n);
143 str[n] = '\0';
146 #endif
148 #if HAVE_TCGETATTR
150 /* Async-safe conversion of errno value to string. */
151 static _GL_ASYNC_SAFE void
152 simple_errno_string (char *str, int errnum)
154 switch (errnum)
156 case EBADF: strcpy (str, "EBADF"); break;
157 case EINTR: strcpy (str, "EINTR"); break;
158 case EINVAL: strcpy (str, "EINVAL"); break;
159 case EIO: strcpy (str, "EIO"); break;
160 case ENOTTY: strcpy (str, "ENOTTY"); break;
161 default: sprintf_integer (str, errnum); break;
165 #endif
167 #if DEBUG_SIGNALS
169 /* Async-safe conversion of signal number to name. */
170 static _GL_ASYNC_SAFE void
171 simple_signal_string (char *str, int sig)
173 switch (sig)
175 /* Fatal signals (see fatal-signal.c). */
176 #ifdef SIGINT
177 case SIGINT: strcpy (str, "SIGINT"); break;
178 #endif
179 #ifdef SIGTERM
180 case SIGTERM: strcpy (str, "SIGTERM"); break;
181 #endif
182 #ifdef SIGHUP
183 case SIGHUP: strcpy (str, "SIGHUP"); break;
184 #endif
185 #ifdef SIGPIPE
186 case SIGPIPE: strcpy (str, "SIGPIPE"); break;
187 #endif
188 #ifdef SIGXCPU
189 case SIGXCPU: strcpy (str, "SIGXCPU"); break;
190 #endif
191 #ifdef SIGXFSZ
192 case SIGXFSZ: strcpy (str, "SIGXFSZ"); break;
193 #endif
194 #ifdef SIGBREAK
195 case SIGBREAK: strcpy (str, "SIGBREAK"); break;
196 #endif
197 /* Stopping signals. */
198 #ifdef SIGTSTP
199 case SIGTSTP: strcpy (str, "SIGTSTP"); break;
200 #endif
201 #ifdef SIGTTIN
202 case SIGTTIN: strcpy (str, "SIGTTIN"); break;
203 #endif
204 #ifdef SIGTTOU
205 case SIGTTOU: strcpy (str, "SIGTTOU"); break;
206 #endif
207 /* Continuing signals. */
208 #ifdef SIGCONT
209 case SIGCONT: strcpy (str, "SIGCONT"); break;
210 #endif
211 default: sprintf_integer (str, sig); break;
215 /* Emit a message that a given signal handler is being run. */
216 static _GL_ASYNC_SAFE void
217 log_signal_handler_called (int sig)
219 char message[100];
220 strcpy (message, "Signal handler for signal ");
221 simple_signal_string (message + strlen (message), sig);
222 strcat (message, " called.\n");
223 log_message (message);
226 #else
228 # define log_signal_handler_called(sig)
230 #endif
233 /* ============================ Signal handling ============================ */
235 /* There are several situations which can cause garbled output on the terminal's
236 screen:
237 (1) When the program calls exit() after calling flush_to_current_style,
238 the program would terminate and leave the terminal in a non-default
239 state.
240 (2) When the program is interrupted through a fatal signal, the terminal
241 would be left in a non-default state.
242 (3) When the program is stopped through a stopping signal, the terminal
243 would be left (for temporary use by other programs) in a non-default
244 state.
245 (4) When a foreground process receives a SIGINT, the kernel(!) prints '^C'.
246 On Linux, the place where this happens is
247 linux-5.0/drivers/tty/n_tty.c:713..730
248 within a call sequence
249 n_tty_receive_signal_char (n_tty.c:1245..1246)
250 -> commit_echoes (n_tty.c:792)
251 -> __process_echoes (n_tty.c:713..730).
252 (5) When a signal is sent, the output buffer is cleared.
253 On Linux, this output buffer consists of the "echo buffer" in the tty
254 and the "output buffer" in the driver. The place where this happens is
255 linux-5.0/drivers/tty/n_tty.c:1133..1140
256 within a call
257 isig (n_tty.c:1133..1140).
259 How do we mitigate these problems?
260 (1) We install an exit handler that restores the terminal to the default
261 state.
262 (2) If tty_control is TTYCTL_PARTIAL or TTYCTL_FULL:
263 For some of the fatal signals (see gnulib's 'fatal-signal' module for
264 the precise list), we install a handler that attempts to restore the
265 terminal to the default state. Since the terminal may be in the middle
266 of outputting an escape sequence at this point, the first escape
267 sequence emitted from this handler may have no effect and produce
268 garbled characters instead. Therefore the handler outputs the cleanup
269 sequence twice.
270 For the other fatal signals, we don't do anything.
271 (3) If tty_control is TTYCTL_PARTIAL or TTYCTL_FULL:
272 For some of the stopping signals (SIGTSTP, SIGTTIN, SIGTTOU), we install
273 a handler that attempts to restore the terminal to the default state.
274 For SIGCONT, we install a handler that does the opposite: it puts the
275 terminal into the desired state again.
276 For SIGSTOP, we cannot do anything.
277 (4) If tty_control is TTYCTL_FULL:
278 The kernel's action depends on L_ECHO(tty) and L_ISIG(tty), that is, on
279 the local modes of the tty (see
280 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
281 section 11.2.5). We don't want to change L_ISIG; hence we change L_ECHO.
282 So, we disable the ECHO local flag of the tty; the equivalent command is
283 'stty -echo'.
284 (5) If tty_control is TTYCTL_FULL:
285 The kernel's action depends on !L_NOFLSH(tty), that is, again on the
286 local modes of the tty (see
287 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
288 section 11.2.5). So, we enable the NOFLSH local flag of the tty; the
289 equivalent command is 'stty noflsh'.
290 For terminals with a baud rate < 9600 this is suboptimal. For this case
291 - where the traditional flushing behaviour makes sense - we would use a
292 technique that involves tcdrain(), TIOCOUTQ, and usleep() when it is OK
293 to disable NOFLSH.
295 Regarding (4) and (5), there is a complication: Changing the local modes is
296 done through tcsetattr(). However, when the process is put into the
297 background, tcsetattr() does not operate the same way as when the process is
298 running in the foreground.
299 To test this kind of behaviour, use the 'color-filter' example like this:
300 $ yes | ./filter '.*'
301 <Ctrl-Z>
302 $ bg 1
303 We have three possible implementation options:
304 * If we don't ignore the signal SIGTTOU:
305 If the TOSTOP bit in the terminal's local mode is clear (command
306 equivalent: 'stty -tostop') and the process is put into the background,
307 normal output would continue (per POSIX
308 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
309 section 11.2.5) but tcsetattr() calls would cause it to stop due to
310 a SIGTTOU signal (per POSIX
311 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html>).
312 Thus, the program would behave differently with term-style-control than
313 without.
314 * If we ignore the signal SIGTTOU when the TOSTOP bit in the terminal's
315 local mode is clear (i.e. when (tc.c_lflag & TOSTOP) == 0):
316 The tcsetattr() calls do not stop the process, but they don't have the
317 desired effect.
318 On Linux, when I put the process into the background and then kill it with
319 signal SIGINT, I can see that the last operation on the terminal settings
320 (as shown by 'strace') is
321 ioctl(1, TCSETSW, {B38400 opost isig icanon echo ...}) = 0
322 and yet, once the process is terminated, the terminal settings contain
323 '-echo', not 'echo'.
324 * Don't call tcsetattr() if the process is not in the foreground.
325 This approach produces reliable results.
327 Blocking some signals while a non-default style is active is *not* useful:
328 - It does not help against (1), since exit() is not a signal.
329 - Signal handlers are the better approach against (2) and (3).
330 - It does not help against (4) and (5), because the kernel's actions happen
331 outside the process. */
332 #define BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT 0
334 /* File descriptor of the currently active 'struct term_style_controller' and
335 'struct term_style_user_data'. */
336 static int volatile term_fd = -1;
338 #if HAVE_TCGETATTR
340 /* Status of the process group of term_fd. */
341 typedef enum
343 PGRP_UNKNOWN = 0, /* term_fd < 0. Unknown status. */
344 PGRP_NO_TTY, /* term_fd >= 0 but is not connected to a tty. */
345 PGRP_IN_FOREGROUND, /* term_fd >= 0 is a tty. This process is running in
346 the foreground. */
347 PGRP_IN_BACKGROUND /* term_fd >= 0 is a tty. This process is running in
348 the background. */
349 } pgrp_status_t;
350 static pgrp_status_t volatile pgrp_status = PGRP_UNKNOWN;
352 /* Update pgrp_status, depending on term_fd. */
353 static _GL_ASYNC_SAFE void
354 update_pgrp_status (void)
356 int fd = term_fd;
357 if (fd < 0)
359 pgrp_status = PGRP_UNKNOWN;
360 log_message ("pgrp_status = PGRP_UNKNOWN\n");
362 else
364 pid_t p = tcgetpgrp (fd);
365 if (p < 0)
367 pgrp_status = PGRP_NO_TTY;
368 log_message ("pgrp_status = PGRP_NO_TTY\n");
370 else
372 /* getpgrp () changes when the process gets put into the background
373 by a shell that implements job control. */
374 if (p == getpgrp ())
376 pgrp_status = PGRP_IN_FOREGROUND;
377 log_message ("pgrp_status = PGRP_IN_FOREGROUND\n");
379 else
381 pgrp_status = PGRP_IN_BACKGROUND;
382 log_message ("pgrp_status = PGRP_IN_BACKGROUND\n");
388 #else
390 # define update_pgrp_status()
392 #endif
394 /* Controller and its user_data that contain information about how to do
395 output. */
396 static const struct term_style_controller * volatile active_controller;
397 static struct term_style_user_data * volatile active_user_data;
399 /* The 'struct term_style_control_data' embedded in active_user_data.
400 Same as
401 (active_controller != NULL
402 ? active_controller->get_control_data (active_user_data)
403 : NULL). */
404 static struct term_style_control_data * volatile active_control_data;
406 /* The fd contained in active_control_data.
407 Same as
408 (active_controller != NULL
409 ? active_control_data->fd
410 : -1). */
411 static int volatile active_fd = -1;
413 /* The exit handler. */
414 static void
415 atexit_handler (void)
417 /* Only do something while some output was started but not completed. */
418 if (active_controller != NULL)
420 active_controller->restore (active_user_data);
421 deactivate_term_non_default_mode (active_controller, active_user_data);
422 #if 0 /* not needed */
423 deactivate_term_style_controller (active_controller, active_user_data);
424 #endif
428 #if HAVE_TCGETATTR
430 /* Return a failure message after tcsetattr() failed. */
431 static _GL_ASYNC_SAFE void
432 tcsetattr_failed (char message[100], const char *caller)
434 int errnum = errno;
435 strcpy (message, caller);
436 strcat (message, ": tcsetattr(fd=");
437 sprintf_integer (message + strlen (message), active_fd);
438 strcat (message, ") failed, errno=");
439 simple_errno_string (message + strlen (message), errnum);
440 strcat (message, "\n");
443 /* True when orig_lflag represents the original tc.c_lflag. */
444 static bool volatile orig_lflag_set;
445 static tcflag_t volatile orig_lflag;
447 /* Modifies the tty's local mode, preparing for non-default terminal state.
448 Used only when the active_control_data's tty_control is TTYCTL_FULL. */
449 static _GL_ASYNC_SAFE void
450 clobber_local_mode (void)
452 /* Here, active_fd == term_fd. */
453 if (pgrp_status == PGRP_IN_FOREGROUND)
455 struct termios tc;
456 if (nonintr_tcgetattr (active_fd, &tc) >= 0)
458 if (!orig_lflag_set)
459 orig_lflag = tc.c_lflag;
460 /* Set orig_lflag_set to true before actually modifying the tty's
461 local mode, because restore_local_mode does nothing if
462 orig_lflag_set is false. */
463 orig_lflag_set = true;
464 tc.c_lflag &= ~ECHO;
465 tc.c_lflag |= NOFLSH;
466 if (nonintr_tcsetattr (active_fd, TCSANOW, &tc) < 0)
468 /* Since tcsetattr failed, restore_local_mode does not need to
469 restore anything. Set orig_lflag_set to false to indicate
470 this. */
471 orig_lflag_set = false;
473 char message[100];
474 tcsetattr_failed (message,
475 "term-style-control:clobber_local_mode");
476 full_write (STDERR_FILENO, message, strlen (message));
483 /* Modifies the tty's local mode, once the terminal is back to the default state.
484 Returns true if ECHO was turned off.
485 Used only when the active_control_data's tty_control is TTYCTL_FULL. */
486 static _GL_ASYNC_SAFE bool
487 restore_local_mode (void)
489 /* Here, active_fd == term_fd. */
490 bool echo_was_off = false;
491 /* Nothing to do if !orig_lflag_set. */
492 if (orig_lflag_set)
494 struct termios tc;
495 if (nonintr_tcgetattr (active_fd, &tc) >= 0)
497 echo_was_off = (tc.c_lflag & ECHO) == 0;
498 tc.c_lflag = orig_lflag;
499 if (nonintr_tcsetattr (active_fd, TCSADRAIN, &tc) < 0)
501 char message[100];
502 tcsetattr_failed (message,
503 "term-style-control:restore_local_mode");
504 full_write (STDERR_FILENO, message, strlen (message));
507 orig_lflag_set = false;
509 return echo_was_off;
512 #endif
514 #if defined SIGCONT
516 /* The list of signals whose default behaviour is to stop or continue the
517 program. */
518 static int const job_control_signals[] =
520 #ifdef SIGTSTP
521 SIGTSTP,
522 #endif
523 #ifdef SIGTTIN
524 SIGTTIN,
525 #endif
526 #ifdef SIGTTOU
527 SIGTTOU,
528 #endif
529 #ifdef SIGCONT
530 SIGCONT,
531 #endif
535 # define num_job_control_signals (SIZEOF (job_control_signals) - 1)
537 #endif
539 /* The following signals are relevant because they output escape sequences to
540 the terminal:
541 - fatal signals,
542 - stopping signals,
543 - continuing signals (SIGCONT). */
545 static sigset_t relevant_signal_set;
546 static bool relevant_signal_set_initialized = false;
548 static void
549 init_relevant_signal_set ()
551 if (!relevant_signal_set_initialized)
553 int fatal_signals[64];
554 size_t num_fatal_signals;
555 size_t i;
557 num_fatal_signals = get_fatal_signals (fatal_signals);
559 sigemptyset (&relevant_signal_set);
560 for (i = 0; i < num_fatal_signals; i++)
561 sigaddset (&relevant_signal_set, fatal_signals[i]);
562 #if defined SIGCONT
563 for (i = 0; i < num_job_control_signals; i++)
564 sigaddset (&relevant_signal_set, job_control_signals[i]);
565 #endif
567 relevant_signal_set_initialized = true;
571 /* Temporarily delay the relevant signals. */
572 static _GL_ASYNC_SAFE inline void
573 block_relevant_signals ()
575 /* The caller must ensure that init_relevant_signal_set () was already
576 called. */
577 if (!relevant_signal_set_initialized)
578 abort ();
580 sigprocmask (SIG_BLOCK, &relevant_signal_set, NULL);
583 /* Stop delaying the relevant signals. */
584 static _GL_ASYNC_SAFE inline void
585 unblock_relevant_signals ()
587 sigprocmask (SIG_UNBLOCK, &relevant_signal_set, NULL);
590 #if defined SIGCONT
592 /* Determines whether a signal is ignored. */
593 static _GL_ASYNC_SAFE bool
594 is_ignored (int sig)
596 struct sigaction action;
598 return (sigaction (sig, NULL, &action) >= 0
599 && get_handler (&action) == SIG_IGN);
602 #endif
604 #if HAVE_TCGETATTR
606 /* Write the same signal marker that the kernel would have printed if ECHO had
607 been turned on. See (4) above.
608 This is a makeshift and is not perfect:
609 - When stderr refers to a different target than active_control_data->fd,
610 it is too hairy to write the signal marker.
611 - In some cases, when the signal was generated right before and delivered
612 right after a clobber_local_mode invocation, the result is that the
613 marker appears twice, e.g. ^C^C. This occurs only with a small
614 probability.
615 - In some cases, when the signal was generated right before and delivered
616 right after a restore_local_mode invocation, the result is that the
617 marker does not appear at all. This occurs only with a small
618 probability.
619 To test this kind of behaviour, use the 'test-term-style-control-yes' example
620 like this:
621 $ ./test-term-style-control-yes
623 static _GL_ASYNC_SAFE void
624 show_signal_marker (int sig)
626 /* Write to stderr, not to active_control_data->fd, because
627 active_control_data->fd is often logged or used with 'less -R'. */
628 if (active_controller != NULL && active_control_data->same_as_stderr)
629 switch (sig)
631 /* The kernel's action when the user presses the INTR key. */
632 case SIGINT:
633 full_write (STDERR_FILENO, "^C", 2); break;
634 /* The kernel's action when the user presses the SUSP key. */
635 case SIGTSTP:
636 full_write (STDERR_FILENO, "^Z", 2); break;
637 /* The kernel's action when the user presses the QUIT key. */
638 case SIGQUIT:
639 full_write (STDERR_FILENO, "^\\", 2); break;
640 default: break;
644 #endif
646 /* The main code of the signal handler for fatal signals and stopping signals.
647 It is reentrant. */
648 static _GL_ASYNC_SAFE void
649 fatal_or_stopping_signal_handler (int sig)
651 #if HAVE_TCGETATTR
652 bool echo_was_off = false;
653 #endif
654 /* Only do something while some output was interrupted. */
655 if (active_controller != NULL
656 && active_control_data->tty_control != TTYCTL_NONE)
658 unsigned int i;
660 /* Block the relevant signals. This is needed, because the output
661 of escape sequences below (usually through tputs invocations) is
662 not reentrant. */
663 block_relevant_signals ();
665 /* Restore the terminal to the default state. */
666 for (i = 0; i < 2; i++)
667 active_controller->async_restore (active_user_data);
668 #if HAVE_TCGETATTR
669 if (active_control_data->tty_control == TTYCTL_FULL)
671 /* Restore the local mode, once the escape sequences output above
672 have reached their destination. */
673 echo_was_off = restore_local_mode ();
675 #endif
677 /* Unblock the relevant signals. */
678 unblock_relevant_signals ();
681 #if HAVE_TCGETATTR
682 if (echo_was_off)
683 show_signal_marker (sig);
684 #endif
687 /* The signal handler for fatal signals.
688 It is reentrant. */
689 static _GL_ASYNC_SAFE void
690 fatal_signal_handler (int sig)
692 log_signal_handler_called (sig);
693 fatal_or_stopping_signal_handler (sig);
696 #if defined SIGCONT
698 /* The signal handler for stopping signals.
699 It is reentrant. */
700 static _GL_ASYNC_SAFE void
701 stopping_signal_handler (int sig)
703 int saved_errno = errno;
705 log_signal_handler_called (sig);
706 fatal_or_stopping_signal_handler (sig);
708 /* Now execute the signal's default action.
709 We reinstall the handler later, during the SIGCONT handler. */
711 struct sigaction action;
712 action.sa_handler = SIG_DFL;
713 action.sa_flags = SA_NODEFER;
714 sigemptyset (&action.sa_mask);
715 sigaction (sig, &action, NULL);
717 errno = saved_errno;
718 raise (sig);
721 /* The signal handler for SIGCONT.
722 It is reentrant. */
723 static _GL_ASYNC_SAFE void
724 continuing_signal_handler (int sig)
726 int saved_errno = errno;
728 log_signal_handler_called (sig);
729 update_pgrp_status ();
730 /* Only do something while some output was interrupted. */
731 if (active_controller != NULL
732 && active_control_data->tty_control != TTYCTL_NONE)
734 /* Reinstall the signals handlers removed in stopping_signal_handler. */
736 unsigned int i;
738 for (i = 0; i < num_job_control_signals; i++)
740 int sig = job_control_signals[i];
742 if (sig != SIGCONT && !is_ignored (sig))
744 struct sigaction action;
745 action.sa_handler = &stopping_signal_handler;
746 /* If we get a stopping or continuing signal while executing
747 stopping_signal_handler or continuing_signal_handler, enter
748 it recursively, since it is reentrant.
749 Hence no SA_RESETHAND. */
750 action.sa_flags = SA_NODEFER;
751 sigemptyset (&action.sa_mask);
752 sigaction (sig, &action, NULL);
757 /* Block the relevant signals. This is needed, because the output of
758 escape sequences done inside the async_set_attributes_from_default
759 call below is not reentrant. */
760 block_relevant_signals ();
762 #if HAVE_TCGETATTR
763 if (active_control_data->tty_control == TTYCTL_FULL)
765 /* Modify the local mode. */
766 clobber_local_mode ();
768 #endif
769 /* Set the terminal attributes. */
770 active_controller->async_set_attributes_from_default (active_user_data);
772 /* Unblock the relevant signals. */
773 unblock_relevant_signals ();
776 errno = saved_errno;
779 /* Ensure the signal handlers are installed.
780 Once they are installed, we leave them installed. It's not worth
781 installing and uninstalling them each time we switch the terminal to a
782 non-default state and back; instead we set active_controller to tell the
783 signal handler whether it has something to do or not. */
785 static void
786 ensure_continuing_signal_handler (void)
788 static bool signal_handler_installed = false;
790 if (!signal_handler_installed)
792 int sig = SIGCONT;
793 struct sigaction action;
794 action.sa_handler = &continuing_signal_handler;
795 /* If we get a stopping or continuing signal while executing
796 continuing_signal_handler, enter it recursively, since it is
797 reentrant. Hence no SA_RESETHAND. */
798 action.sa_flags = SA_NODEFER;
799 sigemptyset (&action.sa_mask);
800 sigaction (sig, &action, NULL);
802 signal_handler_installed = true;
806 #endif
808 static void
809 ensure_other_signal_handlers (void)
811 static bool signal_handlers_installed = false;
813 if (!signal_handlers_installed)
815 /* Install the handlers for the fatal signals. */
816 at_fatal_signal (fatal_signal_handler);
818 #if defined SIGCONT
820 /* Install the handlers for the stopping and continuing signals. */
822 unsigned int i;
824 for (i = 0; i < num_job_control_signals; i++)
826 int sig = job_control_signals[i];
828 if (sig == SIGCONT)
829 /* Already handled in ensure_continuing_signal_handler. */
831 else if (!is_ignored (sig))
833 struct sigaction action;
834 action.sa_handler = &stopping_signal_handler;
835 /* If we get a stopping or continuing signal while executing
836 stopping_signal_handler, enter it recursively, since it is
837 reentrant. Hence no SA_RESETHAND. */
838 action.sa_flags = SA_NODEFER;
839 sigemptyset (&action.sa_mask);
840 sigaction (sig, &action, NULL);
842 #if DEBUG_SIGNALS
843 else
845 fprintf (stderr, "Signal %d is ignored. Not installing a handler!\n",
846 sig);
847 fflush (stderr);
849 #endif
853 #endif
855 signal_handlers_installed = true;
860 /* ============================== Public API ============================== */
862 void
863 activate_term_non_default_mode (const struct term_style_controller *controller,
864 struct term_style_user_data *user_data)
866 struct term_style_control_data *control_data =
867 controller->get_control_data (user_data);
869 if (!control_data->non_default_active)
871 if (control_data->tty_control != TTYCTL_NONE)
872 ensure_other_signal_handlers ();
874 #if BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT
875 /* Block fatal signals, so that a SIGINT or similar doesn't interrupt
876 us without the possibility of restoring the terminal's state.
877 Likewise for SIGTSTP etc. */
878 block_relevant_signals ();
879 #endif
881 /* Enable the exit handler for restoring the terminal's state,
882 and make the signal handlers effective. */
883 if (active_controller != NULL)
885 /* We can't support two active controllers with non-default
886 attributes at the same time. */
887 abort ();
889 /* The uses of 'volatile' (and ISO C 99 section 5.1.2.3.(5)) ensure that
890 we set active_controller to a non-NULL value only after the memory
891 locations active_user_data, active_control_data, active_fd have been
892 filled. */
893 active_fd = control_data->fd;
894 active_control_data = control_data;
895 active_user_data = user_data;
896 active_controller = controller;
898 #if HAVE_TCGETATTR
899 /* Now that the signal handlers are effective, modify the tty. */
900 if (active_control_data->tty_control == TTYCTL_FULL)
902 /* Modify the local mode. */
903 clobber_local_mode ();
905 #endif
907 control_data->non_default_active = true;
911 void
912 deactivate_term_non_default_mode (const struct term_style_controller *controller,
913 struct term_style_user_data *user_data)
915 struct term_style_control_data *control_data =
916 controller->get_control_data (user_data);
918 if (control_data->non_default_active)
920 #if HAVE_TCGETATTR
921 /* Before we make the signal handlers ineffective, modify the tty. */
922 if (active_control_data->tty_control == TTYCTL_FULL)
924 /* Restore the local mode, once the tputs calls from out_attr_change
925 have reached their destination. */
926 restore_local_mode ();
928 #endif
930 /* Disable the exit handler, and make the signal handlers ineffective. */
931 /* The uses of 'volatile' (and ISO C 99 section 5.1.2.3.(5)) ensure that
932 we reset active_user_data, active_control_data, active_fd only after
933 the memory location active_controller has been cleared. */
934 active_controller = NULL;
935 active_user_data = NULL;
936 active_control_data = NULL;
937 active_fd = -1;
939 #if BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT
940 /* Unblock the relevant signals. */
941 unblock_relevant_signals ();
942 #endif
944 control_data->non_default_active = false;
948 void
949 activate_term_style_controller (const struct term_style_controller *controller,
950 struct term_style_user_data *user_data,
951 int fd, ttyctl_t tty_control)
953 struct term_style_control_data *control_data =
954 controller->get_control_data (user_data);
956 control_data->fd = fd;
958 /* Prepare tty control. */
959 if (tty_control == TTYCTL_AUTO)
960 tty_control = TTYCTL_FULL;
961 control_data->tty_control = tty_control;
962 if (control_data->tty_control != TTYCTL_NONE)
963 init_relevant_signal_set ();
964 #if HAVE_TCGETATTR
965 if (control_data->tty_control == TTYCTL_FULL)
967 struct stat statbuf1;
968 struct stat statbuf2;
969 if (fd == STDERR_FILENO
970 || (fstat (fd, &statbuf1) >= 0
971 && fstat (STDERR_FILENO, &statbuf2) >= 0
972 && SAME_INODE (statbuf1, statbuf2)))
973 control_data->same_as_stderr = true;
974 else
975 control_data->same_as_stderr = false;
977 else
978 /* This value is actually not used. */
979 control_data->same_as_stderr = false;
980 #endif
982 control_data->non_default_active = false;
984 /* Start keeping track of the process group status. */
985 term_fd = fd;
986 #if defined SIGCONT
987 ensure_continuing_signal_handler ();
988 #endif
989 update_pgrp_status ();
991 /* Register an exit handler. */
993 static bool registered = false;
994 if (!registered)
996 atexit (atexit_handler);
997 registered = true;
1002 void
1003 deactivate_term_style_controller (const struct term_style_controller *controller,
1004 struct term_style_user_data *user_data)
1006 struct term_style_control_data *control_data =
1007 controller->get_control_data (user_data);
1009 /* Verify that the non-default attributes mode is turned off. */
1010 if (control_data->non_default_active)
1011 abort ();
1013 term_fd = -1;
1014 update_pgrp_status ();