exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / term-style-control.c
blobd18b6b4d69b035978506008934058f1ea4b3875c
1 /* Terminal control for outputting styled text to a terminal.
2 Copyright (C) 2006-2008, 2017, 2019-2024 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 <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #if DEBUG_SIGNALS
32 # include <stdio.h>
33 #endif
34 #if HAVE_TCGETATTR
35 # include <termios.h>
36 # if !defined NOFLSH /* QNX */
37 # define NOFLSH 0
38 # endif
39 #endif
40 #if HAVE_TCGETATTR
41 # include <sys/stat.h>
42 #endif
44 #include "fatal-signal.h"
45 #include "sig-handler.h"
46 #include "full-write.h"
47 #include "same-inode.h"
48 #include "xalloc.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 static void
229 log_signal_handler_called (_GL_UNUSED int sig)
233 #endif
236 /* ============================ Signal handling ============================ */
238 /* There are several situations which can cause garbled output on the terminal's
239 screen:
240 (1) When the program calls exit() after calling flush_to_current_style,
241 the program would terminate and leave the terminal in a non-default
242 state.
243 (2) When the program is interrupted through a fatal signal, the terminal
244 would be left in a non-default state.
245 (3) When the program is stopped through a stopping signal, the terminal
246 would be left (for temporary use by other programs) in a non-default
247 state.
248 (4) When a foreground process receives a SIGINT, the kernel(!) prints '^C'.
249 On Linux, the place where this happens is
250 linux-5.0/drivers/tty/n_tty.c:713..730
251 within a call sequence
252 n_tty_receive_signal_char (n_tty.c:1245..1246)
253 -> commit_echoes (n_tty.c:792)
254 -> __process_echoes (n_tty.c:713..730).
255 (5) When a signal is sent, the output buffer is cleared.
256 On Linux, this output buffer consists of the "echo buffer" in the tty
257 and the "output buffer" in the driver. The place where this happens is
258 linux-5.0/drivers/tty/n_tty.c:1133..1140
259 within a call
260 isig (n_tty.c:1133..1140).
262 How do we mitigate these problems?
263 (1) We install an exit handler that restores the terminal to the default
264 state.
265 (2) If tty_control is TTYCTL_PARTIAL or TTYCTL_FULL:
266 For some of the fatal signals (see gnulib's 'fatal-signal' module for
267 the precise list), we install a handler that attempts to restore the
268 terminal to the default state. Since the terminal may be in the middle
269 of outputting an escape sequence at this point, the first escape
270 sequence emitted from this handler may have no effect and produce
271 garbled characters instead. Therefore the handler outputs the cleanup
272 sequence twice.
273 For the other fatal signals, we don't do anything.
274 (3) If tty_control is TTYCTL_PARTIAL or TTYCTL_FULL:
275 For some of the stopping signals (SIGTSTP, SIGTTIN, SIGTTOU), we install
276 a handler that attempts to restore the terminal to the default state.
277 For SIGCONT, we install a handler that does the opposite: it puts the
278 terminal into the desired state again.
279 For SIGSTOP, we cannot do anything.
280 (4) If tty_control is TTYCTL_FULL:
281 The kernel's action depends on L_ECHO(tty) and L_ISIG(tty), that is, on
282 the local modes of the tty (see
283 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
284 section 11.2.5). We don't want to change L_ISIG; hence we change L_ECHO.
285 So, we disable the ECHO local flag of the tty; the equivalent command is
286 'stty -echo'.
287 (5) If tty_control is TTYCTL_FULL:
288 The kernel's action depends on !L_NOFLSH(tty), that is, again on the
289 local modes of the tty (see
290 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
291 section 11.2.5). So, we enable the NOFLSH local flag of the tty; the
292 equivalent command is 'stty noflsh'.
293 For terminals with a baud rate < 9600 this is suboptimal. For this case
294 - where the traditional flushing behaviour makes sense - we would use a
295 technique that involves tcdrain(), TIOCOUTQ, and usleep() when it is OK
296 to disable NOFLSH.
298 Regarding (4) and (5), there is a complication: Changing the local modes is
299 done through tcsetattr(). However, when the process is put into the
300 background, tcsetattr() does not operate the same way as when the process is
301 running in the foreground.
302 To test this kind of behaviour, use the 'color-filter' example like this:
303 $ yes | ./filter '.*'
304 <Ctrl-Z>
305 $ bg 1
306 We have three possible implementation options:
307 * If we don't ignore the signal SIGTTOU:
308 If the TOSTOP bit in the terminal's local mode is clear (command
309 equivalent: 'stty -tostop') and the process is put into the background,
310 normal output would continue (per POSIX
311 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
312 section 11.2.5) but tcsetattr() calls would cause it to stop due to
313 a SIGTTOU signal (per POSIX
314 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html>).
315 Thus, the program would behave differently with term-style-control than
316 without.
317 * If we ignore the signal SIGTTOU when the TOSTOP bit in the terminal's
318 local mode is clear (i.e. when (tc.c_lflag & TOSTOP) == 0):
319 The tcsetattr() calls do not stop the process, but they don't have the
320 desired effect.
321 On Linux, when I put the process into the background and then kill it with
322 signal SIGINT, I can see that the last operation on the terminal settings
323 (as shown by 'strace') is
324 ioctl(1, TCSETSW, {B38400 opost isig icanon echo ...}) = 0
325 and yet, once the process is terminated, the terminal settings contain
326 '-echo', not 'echo'.
327 * Don't call tcsetattr() if the process is not in the foreground.
328 This approach produces reliable results.
330 Blocking some signals while a non-default style is active is *not* useful:
331 - It does not help against (1), since exit() is not a signal.
332 - Signal handlers are the better approach against (2) and (3).
333 - It does not help against (4) and (5), because the kernel's actions happen
334 outside the process. */
335 #define BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT 0
337 /* File descriptor of the currently active 'struct term_style_controller' and
338 'struct term_style_user_data'. */
339 static int volatile term_fd = -1;
341 #if HAVE_TCGETATTR
343 /* Status of the process group of term_fd. */
344 typedef enum
346 PGRP_UNKNOWN = 0, /* term_fd < 0. Unknown status. */
347 PGRP_NO_TTY, /* term_fd >= 0 but is not connected to a tty. */
348 PGRP_IN_FOREGROUND, /* term_fd >= 0 is a tty. This process is running in
349 the foreground. */
350 PGRP_IN_BACKGROUND /* term_fd >= 0 is a tty. This process is running in
351 the background. */
352 } pgrp_status_t;
353 static pgrp_status_t volatile pgrp_status = PGRP_UNKNOWN;
355 /* Update pgrp_status, depending on term_fd. */
356 static _GL_ASYNC_SAFE void
357 update_pgrp_status (void)
359 int fd = term_fd;
360 if (fd < 0)
362 pgrp_status = PGRP_UNKNOWN;
363 log_message ("pgrp_status = PGRP_UNKNOWN\n");
365 else
367 pid_t p = tcgetpgrp (fd);
368 if (p < 0)
370 pgrp_status = PGRP_NO_TTY;
371 log_message ("pgrp_status = PGRP_NO_TTY\n");
373 else
375 /* getpgrp () changes when the process gets put into the background
376 by a shell that implements job control. */
377 if (p == getpgrp ())
379 pgrp_status = PGRP_IN_FOREGROUND;
380 log_message ("pgrp_status = PGRP_IN_FOREGROUND\n");
382 else
384 pgrp_status = PGRP_IN_BACKGROUND;
385 log_message ("pgrp_status = PGRP_IN_BACKGROUND\n");
391 #else
393 # define update_pgrp_status()
395 #endif
397 /* Controller and its user_data that contain information about how to do
398 output. */
399 static const struct term_style_controller * volatile active_controller;
400 static struct term_style_user_data * volatile active_user_data;
402 /* The 'struct term_style_control_data' embedded in active_user_data.
403 Same as
404 (active_controller != NULL
405 ? active_controller->get_control_data (active_user_data)
406 : NULL). */
407 static struct term_style_control_data * volatile active_control_data;
409 /* The fd contained in active_control_data.
410 Same as
411 (active_controller != NULL
412 ? active_control_data->fd
413 : -1). */
414 static int volatile active_fd = -1;
416 /* The exit handler. */
417 static void
418 atexit_handler (void)
420 /* Only do something while some output was started but not completed. */
421 if (active_controller != NULL)
423 active_controller->restore (active_user_data);
424 deactivate_term_non_default_mode (active_controller, active_user_data);
425 #if 0 /* not needed */
426 deactivate_term_style_controller (active_controller, active_user_data);
427 #endif
431 #if HAVE_TCGETATTR
433 /* Return a failure message after tcsetattr() failed. */
434 static _GL_ASYNC_SAFE void
435 tcsetattr_failed (char message[100], const char *caller)
437 int errnum = errno;
438 strcpy (message, caller);
439 strcat (message, ": tcsetattr(fd=");
440 sprintf_integer (message + strlen (message), active_fd);
441 strcat (message, ") failed, errno=");
442 simple_errno_string (message + strlen (message), errnum);
443 strcat (message, "\n");
446 /* True when orig_lflag represents the original tc.c_lflag. */
447 static bool volatile orig_lflag_set;
448 static tcflag_t volatile orig_lflag;
450 /* Modifies the tty's local mode, preparing for non-default terminal state.
451 Used only when the active_control_data's tty_control is TTYCTL_FULL. */
452 static _GL_ASYNC_SAFE void
453 clobber_local_mode (void)
455 /* Here, active_fd == term_fd. */
456 if (pgrp_status == PGRP_IN_FOREGROUND)
458 struct termios tc;
459 if (nonintr_tcgetattr (active_fd, &tc) >= 0)
461 if (!orig_lflag_set)
462 orig_lflag = tc.c_lflag;
463 /* Set orig_lflag_set to true before actually modifying the tty's
464 local mode, because restore_local_mode does nothing if
465 orig_lflag_set is false. */
466 orig_lflag_set = true;
467 tc.c_lflag &= ~ECHO;
468 tc.c_lflag |= NOFLSH;
469 if (nonintr_tcsetattr (active_fd, TCSANOW, &tc) < 0)
471 /* Since tcsetattr failed, restore_local_mode does not need to
472 restore anything. Set orig_lflag_set to false to indicate
473 this. */
474 orig_lflag_set = false;
476 char message[100];
477 tcsetattr_failed (message,
478 "term-style-control:clobber_local_mode");
479 full_write (STDERR_FILENO, message, strlen (message));
486 /* Modifies the tty's local mode, once the terminal is back to the default state.
487 Returns true if ECHO was turned off.
488 Used only when the active_control_data's tty_control is TTYCTL_FULL. */
489 static _GL_ASYNC_SAFE bool
490 restore_local_mode (void)
492 /* Here, active_fd == term_fd. */
493 bool echo_was_off = false;
494 /* Nothing to do if !orig_lflag_set. */
495 if (orig_lflag_set)
497 struct termios tc;
498 if (nonintr_tcgetattr (active_fd, &tc) >= 0)
500 echo_was_off = (tc.c_lflag & ECHO) == 0;
501 tc.c_lflag = orig_lflag;
502 if (nonintr_tcsetattr (active_fd, TCSADRAIN, &tc) < 0)
504 char message[100];
505 tcsetattr_failed (message,
506 "term-style-control:restore_local_mode");
507 full_write (STDERR_FILENO, message, strlen (message));
510 orig_lflag_set = false;
512 return echo_was_off;
515 #endif
517 #if defined SIGCONT
519 /* The list of signals whose default behaviour is to stop or continue the
520 program. */
521 static int const job_control_signals[] =
523 #ifdef SIGTSTP
524 SIGTSTP,
525 #endif
526 #ifdef SIGTTIN
527 SIGTTIN,
528 #endif
529 #ifdef SIGTTOU
530 SIGTTOU,
531 #endif
532 #ifdef SIGCONT
533 SIGCONT,
534 #endif
538 # define num_job_control_signals (SIZEOF (job_control_signals) - 1)
540 #endif
542 /* The following signals are relevant because they output escape sequences to
543 the terminal:
544 - fatal signals,
545 - stopping signals,
546 - continuing signals (SIGCONT). */
548 static sigset_t relevant_signal_set;
549 static bool relevant_signal_set_initialized = false;
551 static void
552 init_relevant_signal_set ()
554 if (!relevant_signal_set_initialized)
556 int fatal_signals[64];
557 size_t num_fatal_signals;
558 size_t i;
560 num_fatal_signals = get_fatal_signals (fatal_signals);
562 sigemptyset (&relevant_signal_set);
563 for (i = 0; i < num_fatal_signals; i++)
564 sigaddset (&relevant_signal_set, fatal_signals[i]);
565 #if defined SIGCONT
566 for (i = 0; i < num_job_control_signals; i++)
567 sigaddset (&relevant_signal_set, job_control_signals[i]);
568 #endif
570 relevant_signal_set_initialized = true;
574 /* Temporarily delay the relevant signals. */
575 static _GL_ASYNC_SAFE inline void
576 block_relevant_signals ()
578 /* The caller must ensure that init_relevant_signal_set () was already
579 called. */
580 if (!relevant_signal_set_initialized)
581 abort ();
583 sigprocmask (SIG_BLOCK, &relevant_signal_set, NULL);
586 /* Stop delaying the relevant signals. */
587 static _GL_ASYNC_SAFE inline void
588 unblock_relevant_signals ()
590 sigprocmask (SIG_UNBLOCK, &relevant_signal_set, NULL);
593 #if defined SIGCONT
595 /* Determines whether a signal is ignored. */
596 static _GL_ASYNC_SAFE bool
597 is_ignored (int sig)
599 struct sigaction action;
601 return (sigaction (sig, NULL, &action) >= 0
602 && get_handler (&action) == SIG_IGN);
605 #endif
607 #if HAVE_TCGETATTR
609 /* Write the same signal marker that the kernel would have printed if ECHO had
610 been turned on. See (4) above.
611 This is a makeshift and is not perfect:
612 - When stderr refers to a different target than active_control_data->fd,
613 it is too hairy to write the signal marker.
614 - In some cases, when the signal was generated right before and delivered
615 right after a clobber_local_mode invocation, the result is that the
616 marker appears twice, e.g. ^C^C. This occurs only with a small
617 probability.
618 - In some cases, when the signal was generated right before and delivered
619 right after a restore_local_mode invocation, the result is that the
620 marker does not appear at all. This occurs only with a small
621 probability.
622 To test this kind of behaviour, use the 'test-term-style-control-yes' example
623 like this:
624 $ ./test-term-style-control-yes
626 static _GL_ASYNC_SAFE void
627 show_signal_marker (int sig)
629 /* Write to stderr, not to active_control_data->fd, because
630 active_control_data->fd is often logged or used with 'less -R'. */
631 if (active_controller != NULL && active_control_data->same_as_stderr)
632 switch (sig)
634 /* The kernel's action when the user presses the INTR key. */
635 case SIGINT:
636 full_write (STDERR_FILENO, "^C", 2); break;
637 /* The kernel's action when the user presses the SUSP key. */
638 case SIGTSTP:
639 full_write (STDERR_FILENO, "^Z", 2); break;
640 /* The kernel's action when the user presses the QUIT key. */
641 case SIGQUIT:
642 full_write (STDERR_FILENO, "^\\", 2); break;
643 default: break;
647 #endif
649 /* The main code of the signal handler for fatal signals and stopping signals.
650 It is reentrant. */
651 static _GL_ASYNC_SAFE void
652 fatal_or_stopping_signal_handler (int sig)
654 #if HAVE_TCGETATTR
655 bool echo_was_off = false;
656 #endif
657 /* Only do something while some output was interrupted. */
658 if (active_controller != NULL
659 && active_control_data->tty_control != TTYCTL_NONE)
661 unsigned int i;
663 /* Block the relevant signals. This is needed, because the output
664 of escape sequences below (usually through tputs invocations) is
665 not reentrant. */
666 block_relevant_signals ();
668 /* Restore the terminal to the default state. */
669 for (i = 0; i < 2; i++)
670 active_controller->async_restore (active_user_data);
671 #if HAVE_TCGETATTR
672 if (active_control_data->tty_control == TTYCTL_FULL)
674 /* Restore the local mode, once the escape sequences output above
675 have reached their destination. */
676 echo_was_off = restore_local_mode ();
678 #endif
680 /* Unblock the relevant signals. */
681 unblock_relevant_signals ();
684 #if HAVE_TCGETATTR
685 if (echo_was_off)
686 show_signal_marker (sig);
687 #endif
690 /* The signal handler for fatal signals.
691 It is reentrant. */
692 static _GL_ASYNC_SAFE void
693 fatal_signal_handler (int sig)
695 log_signal_handler_called (sig);
696 fatal_or_stopping_signal_handler (sig);
699 #if defined SIGCONT
701 /* The signal handler for stopping signals.
702 It is reentrant. */
703 static _GL_ASYNC_SAFE void
704 stopping_signal_handler (int sig)
706 int saved_errno = errno;
708 log_signal_handler_called (sig);
709 fatal_or_stopping_signal_handler (sig);
711 /* Now execute the signal's default action.
712 We reinstall the handler later, during the SIGCONT handler. */
714 struct sigaction action;
715 action.sa_handler = SIG_DFL;
716 action.sa_flags = SA_NODEFER;
717 sigemptyset (&action.sa_mask);
718 sigaction (sig, &action, NULL);
720 errno = saved_errno;
721 raise (sig);
724 /* The signal handler for SIGCONT.
725 It is reentrant. */
726 static _GL_ASYNC_SAFE void
727 continuing_signal_handler (int sigcont)
729 int saved_errno = errno;
731 log_signal_handler_called (sigcont);
732 update_pgrp_status ();
733 /* Only do something while some output was interrupted. */
734 if (active_controller != NULL
735 && active_control_data->tty_control != TTYCTL_NONE)
737 /* Reinstall the signals handlers removed in stopping_signal_handler. */
739 unsigned int i;
741 for (i = 0; i < num_job_control_signals; i++)
743 int sig = job_control_signals[i];
745 if (sig != SIGCONT && !is_ignored (sig))
747 struct sigaction action;
748 action.sa_handler = &stopping_signal_handler;
749 /* If we get a stopping or continuing signal while executing
750 stopping_signal_handler or continuing_signal_handler, enter
751 it recursively, since it is reentrant.
752 Hence no SA_RESETHAND. */
753 action.sa_flags = SA_NODEFER;
754 sigemptyset (&action.sa_mask);
755 sigaction (sig, &action, NULL);
760 /* Block the relevant signals. This is needed, because the output of
761 escape sequences done inside the async_set_attributes_from_default
762 call below is not reentrant. */
763 block_relevant_signals ();
765 #if HAVE_TCGETATTR
766 if (active_control_data->tty_control == TTYCTL_FULL)
768 /* Modify the local mode. */
769 clobber_local_mode ();
771 #endif
772 /* Set the terminal attributes. */
773 active_controller->async_set_attributes_from_default (active_user_data);
775 /* Unblock the relevant signals. */
776 unblock_relevant_signals ();
779 errno = saved_errno;
782 /* Ensure the signal handlers are installed.
783 Once they are installed, we leave them installed. It's not worth
784 installing and uninstalling them each time we switch the terminal to a
785 non-default state and back; instead we set active_controller to tell the
786 signal handler whether it has something to do or not. */
788 static void
789 ensure_continuing_signal_handler (void)
791 static bool signal_handler_installed = false;
793 if (!signal_handler_installed)
795 int sig = SIGCONT;
796 struct sigaction action;
797 action.sa_handler = &continuing_signal_handler;
798 /* If we get a stopping or continuing signal while executing
799 continuing_signal_handler, enter it recursively, since it is
800 reentrant. Hence no SA_RESETHAND. */
801 action.sa_flags = SA_NODEFER;
802 sigemptyset (&action.sa_mask);
803 sigaction (sig, &action, NULL);
805 signal_handler_installed = true;
809 #endif
811 static void
812 ensure_other_signal_handlers (void)
814 static bool signal_handlers_installed = false;
816 if (!signal_handlers_installed)
818 /* Install the handlers for the fatal signals. */
819 if (at_fatal_signal (fatal_signal_handler) < 0)
820 xalloc_die ();
822 #if defined SIGCONT
824 /* Install the handlers for the stopping and continuing signals. */
826 unsigned int i;
828 for (i = 0; i < num_job_control_signals; i++)
830 int sig = job_control_signals[i];
832 if (sig == SIGCONT)
833 /* Already handled in ensure_continuing_signal_handler. */
835 else if (!is_ignored (sig))
837 struct sigaction action;
838 action.sa_handler = &stopping_signal_handler;
839 /* If we get a stopping or continuing signal while executing
840 stopping_signal_handler, enter it recursively, since it is
841 reentrant. Hence no SA_RESETHAND. */
842 action.sa_flags = SA_NODEFER;
843 sigemptyset (&action.sa_mask);
844 sigaction (sig, &action, NULL);
846 #if DEBUG_SIGNALS
847 else
849 fprintf (stderr, "Signal %d is ignored. Not installing a handler!\n",
850 sig);
851 fflush (stderr);
853 #endif
857 #endif
859 signal_handlers_installed = true;
864 /* ============================== Public API ============================== */
866 void
867 activate_term_non_default_mode (const struct term_style_controller *controller,
868 struct term_style_user_data *user_data)
870 struct term_style_control_data *control_data =
871 controller->get_control_data (user_data);
873 if (!control_data->non_default_active)
875 if (control_data->tty_control != TTYCTL_NONE)
876 ensure_other_signal_handlers ();
878 #if BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT
879 /* Block fatal signals, so that a SIGINT or similar doesn't interrupt
880 us without the possibility of restoring the terminal's state.
881 Likewise for SIGTSTP etc. */
882 block_relevant_signals ();
883 #endif
885 /* Enable the exit handler for restoring the terminal's state,
886 and make the signal handlers effective. */
887 if (active_controller != NULL)
889 /* We can't support two active controllers with non-default
890 attributes at the same time. */
891 abort ();
893 /* The uses of 'volatile' (and ISO C 99 section 5.1.2.3.(5)) ensure that
894 we set active_controller to a non-NULL value only after the memory
895 locations active_user_data, active_control_data, active_fd have been
896 filled. */
897 active_fd = control_data->fd;
898 active_control_data = control_data;
899 active_user_data = user_data;
900 active_controller = controller;
902 #if HAVE_TCGETATTR
903 /* Now that the signal handlers are effective, modify the tty. */
904 if (active_control_data->tty_control == TTYCTL_FULL)
906 /* Modify the local mode. */
907 clobber_local_mode ();
909 #endif
911 control_data->non_default_active = true;
915 void
916 deactivate_term_non_default_mode (const struct term_style_controller *controller,
917 struct term_style_user_data *user_data)
919 struct term_style_control_data *control_data =
920 controller->get_control_data (user_data);
922 if (control_data->non_default_active)
924 #if HAVE_TCGETATTR
925 /* Before we make the signal handlers ineffective, modify the tty. */
926 if (active_control_data->tty_control == TTYCTL_FULL)
928 /* Restore the local mode, once the tputs calls from out_attr_change
929 have reached their destination. */
930 restore_local_mode ();
932 #endif
934 /* Disable the exit handler, and make the signal handlers ineffective. */
935 /* The uses of 'volatile' (and ISO C 99 section 5.1.2.3.(5)) ensure that
936 we reset active_user_data, active_control_data, active_fd only after
937 the memory location active_controller has been cleared. */
938 active_controller = NULL;
939 active_user_data = NULL;
940 active_control_data = NULL;
941 active_fd = -1;
943 #if BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT
944 /* Unblock the relevant signals. */
945 unblock_relevant_signals ();
946 #endif
948 control_data->non_default_active = false;
952 void
953 activate_term_style_controller (const struct term_style_controller *controller,
954 struct term_style_user_data *user_data,
955 int fd, ttyctl_t tty_control)
957 struct term_style_control_data *control_data =
958 controller->get_control_data (user_data);
960 control_data->fd = fd;
962 /* Prepare tty control. */
963 if (tty_control == TTYCTL_AUTO)
964 tty_control = TTYCTL_FULL;
965 control_data->tty_control = tty_control;
966 if (control_data->tty_control != TTYCTL_NONE)
967 init_relevant_signal_set ();
968 #if HAVE_TCGETATTR
969 if (control_data->tty_control == TTYCTL_FULL)
971 struct stat statbuf1;
972 struct stat statbuf2;
973 if (fd == STDERR_FILENO
974 || (fstat (fd, &statbuf1) >= 0
975 && fstat (STDERR_FILENO, &statbuf2) >= 0
976 && psame_inode (&statbuf1, &statbuf2)))
977 control_data->same_as_stderr = true;
978 else
979 control_data->same_as_stderr = false;
981 else
982 /* This value is actually not used. */
983 control_data->same_as_stderr = false;
984 #endif
986 control_data->non_default_active = false;
988 /* Start keeping track of the process group status. */
989 term_fd = fd;
990 #if defined SIGCONT
991 ensure_continuing_signal_handler ();
992 #endif
993 update_pgrp_status ();
995 /* Register an exit handler. */
997 static bool registered = false;
998 if (!registered)
1000 atexit (atexit_handler);
1001 registered = true;
1006 void
1007 deactivate_term_style_controller (const struct term_style_controller *controller,
1008 struct term_style_user_data *user_data)
1010 struct term_style_control_data *control_data =
1011 controller->get_control_data (user_data);
1013 /* Verify that the non-default attributes mode is turned off. */
1014 if (control_data->non_default_active)
1015 abort ();
1017 term_fd = -1;
1018 update_pgrp_status ();