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/>. */
21 #include "term-style-control.h"
23 /* Set to 1 to get debugging output regarding signals. */
24 #define DEBUG_SIGNALS 0
37 # if !defined NOFLSH /* QNX */
42 # include <sys/stat.h>
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. */
62 nonintr_tcgetattr (int fd
, struct termios
*tcp
)
67 retval
= tcgetattr (fd
, tcp
);
68 while (retval
< 0 && errno
== EINTR
);
74 nonintr_tcsetattr (int fd
, int flush_mode
, const struct termios
*tcp
)
79 retval
= tcsetattr (fd
, flush_mode
, tcp
);
80 while (retval
< 0 && errno
== EINTR
);
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(). */
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
));
111 # define log_message(message)
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
)
129 y
= (unsigned int) (-1 - x
) + 1;
134 p
= buf
+ sizeof (buf
);
137 *--p
= '0' + (y
% 10);
141 n
= buf
+ sizeof (buf
) - p
;
150 /* Async-safe conversion of errno value to string. */
151 static _GL_ASYNC_SAFE
void
152 simple_errno_string (char *str
, int 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;
169 /* Async-safe conversion of signal number to name. */
170 static _GL_ASYNC_SAFE
void
171 simple_signal_string (char *str
, int sig
)
175 /* Fatal signals (see fatal-signal.c). */
177 case SIGINT
: strcpy (str
, "SIGINT"); break;
180 case SIGTERM
: strcpy (str
, "SIGTERM"); break;
183 case SIGHUP
: strcpy (str
, "SIGHUP"); break;
186 case SIGPIPE
: strcpy (str
, "SIGPIPE"); break;
189 case SIGXCPU
: strcpy (str
, "SIGXCPU"); break;
192 case SIGXFSZ
: strcpy (str
, "SIGXFSZ"); break;
195 case SIGBREAK
: strcpy (str
, "SIGBREAK"); break;
197 /* Stopping signals. */
199 case SIGTSTP
: strcpy (str
, "SIGTSTP"); break;
202 case SIGTTIN
: strcpy (str
, "SIGTTIN"); break;
205 case SIGTTOU
: strcpy (str
, "SIGTTOU"); break;
207 /* Continuing signals. */
209 case SIGCONT
: strcpy (str
, "SIGCONT"); break;
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
)
220 strcpy (message
, "Signal handler for signal ");
221 simple_signal_string (message
+ strlen (message
), sig
);
222 strcat (message
, " called.\n");
223 log_message (message
);
228 # define log_signal_handler_called(sig)
233 /* ============================ Signal handling ============================ */
235 /* There are several situations which can cause garbled output on the terminal's
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
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
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
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
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
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
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
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 '.*'
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
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
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
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;
340 /* Status of the process group of term_fd. */
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
347 PGRP_IN_BACKGROUND
/* term_fd >= 0 is a tty. This process is running in
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)
359 pgrp_status
= PGRP_UNKNOWN
;
360 log_message ("pgrp_status = PGRP_UNKNOWN\n");
364 pid_t p
= tcgetpgrp (fd
);
367 pgrp_status
= PGRP_NO_TTY
;
368 log_message ("pgrp_status = PGRP_NO_TTY\n");
372 /* getpgrp () changes when the process gets put into the background
373 by a shell that implements job control. */
376 pgrp_status
= PGRP_IN_FOREGROUND
;
377 log_message ("pgrp_status = PGRP_IN_FOREGROUND\n");
381 pgrp_status
= PGRP_IN_BACKGROUND
;
382 log_message ("pgrp_status = PGRP_IN_BACKGROUND\n");
390 # define update_pgrp_status()
394 /* Controller and its user_data that contain information about how to do
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.
401 (active_controller != NULL
402 ? active_controller->get_control_data (active_user_data)
404 static struct term_style_control_data
* volatile active_control_data
;
406 /* The fd contained in active_control_data.
408 (active_controller != NULL
409 ? active_control_data->fd
411 static int volatile active_fd
= -1;
413 /* The exit handler. */
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
);
430 /* Return a failure message after tcsetattr() failed. */
431 static _GL_ASYNC_SAFE
void
432 tcsetattr_failed (char message
[100], const char *caller
)
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
)
456 if (nonintr_tcgetattr (active_fd
, &tc
) >= 0)
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;
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
471 orig_lflag_set
= false;
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. */
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)
502 tcsetattr_failed (message
,
503 "term-style-control:restore_local_mode");
504 full_write (STDERR_FILENO
, message
, strlen (message
));
507 orig_lflag_set
= false;
516 /* The list of signals whose default behaviour is to stop or continue the
518 static int const job_control_signals
[] =
535 # define num_job_control_signals (SIZEOF (job_control_signals) - 1)
539 /* The following signals are relevant because they output escape sequences to
543 - continuing signals (SIGCONT). */
545 static sigset_t relevant_signal_set
;
546 static bool relevant_signal_set_initialized
= false;
549 init_relevant_signal_set ()
551 if (!relevant_signal_set_initialized
)
553 int fatal_signals
[64];
554 size_t num_fatal_signals
;
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
]);
563 for (i
= 0; i
< num_job_control_signals
; i
++)
564 sigaddset (&relevant_signal_set
, job_control_signals
[i
]);
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
577 if (!relevant_signal_set_initialized
)
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
);
592 /* Determines whether a signal is ignored. */
593 static _GL_ASYNC_SAFE
bool
596 struct sigaction action
;
598 return (sigaction (sig
, NULL
, &action
) >= 0
599 && get_handler (&action
) == SIG_IGN
);
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
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
619 To test this kind of behaviour, use the 'test-term-style-control-yes' example
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
)
631 /* The kernel's action when the user presses the INTR key. */
633 full_write (STDERR_FILENO
, "^C", 2); break;
634 /* The kernel's action when the user presses the SUSP key. */
636 full_write (STDERR_FILENO
, "^Z", 2); break;
637 /* The kernel's action when the user presses the QUIT key. */
639 full_write (STDERR_FILENO
, "^\\", 2); break;
646 /* The main code of the signal handler for fatal signals and stopping signals.
648 static _GL_ASYNC_SAFE
void
649 fatal_or_stopping_signal_handler (int sig
)
652 bool echo_was_off
= false;
654 /* Only do something while some output was interrupted. */
655 if (active_controller
!= NULL
656 && active_control_data
->tty_control
!= TTYCTL_NONE
)
660 /* Block the relevant signals. This is needed, because the output
661 of escape sequences below (usually through tputs invocations) is
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
);
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 ();
677 /* Unblock the relevant signals. */
678 unblock_relevant_signals ();
683 show_signal_marker (sig
);
687 /* The signal handler for fatal signals.
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
);
698 /* The signal handler for stopping signals.
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
);
721 /* The signal handler for SIGCONT.
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. */
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 ();
763 if (active_control_data
->tty_control
== TTYCTL_FULL
)
765 /* Modify the local mode. */
766 clobber_local_mode ();
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 ();
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. */
786 ensure_continuing_signal_handler (void)
788 static bool signal_handler_installed
= false;
790 if (!signal_handler_installed
)
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;
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
);
820 /* Install the handlers for the stopping and continuing signals. */
824 for (i
= 0; i
< num_job_control_signals
; i
++)
826 int sig
= job_control_signals
[i
];
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
);
845 fprintf (stderr
, "Signal %d is ignored. Not installing a handler!\n",
855 signal_handlers_installed
= true;
860 /* ============================== Public API ============================== */
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 ();
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. */
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
893 active_fd
= control_data
->fd
;
894 active_control_data
= control_data
;
895 active_user_data
= user_data
;
896 active_controller
= controller
;
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 ();
907 control_data
->non_default_active
= true;
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
)
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 ();
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
;
939 #if BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT
940 /* Unblock the relevant signals. */
941 unblock_relevant_signals ();
944 control_data
->non_default_active
= false;
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 ();
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;
975 control_data
->same_as_stderr
= false;
978 /* This value is actually not used. */
979 control_data
->same_as_stderr
= false;
982 control_data
->non_default_active
= false;
984 /* Start keeping track of the process group status. */
987 ensure_continuing_signal_handler ();
989 update_pgrp_status ();
991 /* Register an exit handler. */
993 static bool registered
= false;
996 atexit (atexit_handler
);
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
)
1014 update_pgrp_status ();