root/maint/gnulib/lib/term-style-control.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nonintr_tcgetattr
  2. nonintr_tcsetattr
  3. log_message
  4. sprintf_integer
  5. simple_errno_string
  6. simple_signal_string
  7. log_signal_handler_called
  8. update_pgrp_status
  9. atexit_handler
  10. tcsetattr_failed
  11. clobber_local_mode
  12. restore_local_mode
  13. init_relevant_signal_set
  14. block_relevant_signals
  15. unblock_relevant_signals
  16. is_ignored
  17. show_signal_marker
  18. fatal_or_stopping_signal_handler
  19. fatal_signal_handler
  20. stopping_signal_handler
  21. continuing_signal_handler
  22. ensure_continuing_signal_handler
  23. ensure_other_signal_handlers
  24. activate_term_non_default_mode
  25. deactivate_term_non_default_mode
  26. activate_term_style_controller
  27. deactivate_term_style_controller

   1 /* Terminal control for outputting styled text to a terminal.
   2    Copyright (C) 2006-2008, 2017, 2019-2021 Free Software Foundation, Inc.
   3    Written by Bruno Haible <bruno@clisp.org>, 2019.
   4 
   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.
   9 
  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.
  14 
  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/>.  */
  17 
  18 #include <config.h>
  19 
  20 /* Specification.  */
  21 #include "term-style-control.h"
  22 
  23 /* Set to 1 to get debugging output regarding signals.  */
  24 #define DEBUG_SIGNALS 0
  25 
  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
  44 
  45 #include "fatal-signal.h"
  46 #include "sig-handler.h"
  47 #include "full-write.h"
  48 #include "same-inode.h"
  49 #include "xalloc.h"
  50 
  51 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
  52 
  53 
  54 /* ============================ EINTR handling ============================ */
  55 
  56 /* EINTR handling for tcgetattr(), tcsetattr().
  57    These functions can return -1/EINTR even when we don't have any
  58    signal handlers set up, namely when we get interrupted via SIGSTOP.  */
  59 
  60 #if HAVE_TCGETATTR
  61 
  62 static inline int
  63 nonintr_tcgetattr (int fd, struct termios *tcp)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65   int retval;
  66 
  67   do
  68     retval = tcgetattr (fd, tcp);
  69   while (retval < 0 && errno == EINTR);
  70 
  71   return retval;
  72 }
  73 
  74 static inline int
  75 nonintr_tcsetattr (int fd, int flush_mode, const struct termios *tcp)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77   int retval;
  78 
  79   do
  80     retval = tcsetattr (fd, flush_mode, tcp);
  81   while (retval < 0 && errno == EINTR);
  82 
  83   return retval;
  84 }
  85 
  86 #endif
  87 
  88 
  89 /* ========================== Logging primitives ========================== */
  90 
  91 /* We need logging, especially for the signal handling, because
  92      - Debugging through gdb is hardly possible, because gdb produces output
  93        by itself and interferes with the process states.
  94      - strace is buggy when it comes to SIGTSTP handling:  By default, it
  95        sends the process a SIGSTOP signal instead of SIGTSTP.  It supports
  96        an option '-D -I4' to mitigate this, though.  Also, race conditions
  97        appear with different probability with and without strace.
  98    fprintf(stderr) is not possible within async-safe code, because fprintf()
  99    may invoke malloc().  */
 100 
 101 #if DEBUG_SIGNALS
 102 
 103 /* Log a simple message.  */
 104 static _GL_ASYNC_SAFE void
 105 log_message (const char *message)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107   full_write (STDERR_FILENO, message, strlen (message));
 108 }
 109 
 110 #else
 111 
 112 # define log_message(message)
 113 
 114 #endif
 115 
 116 #if HAVE_TCGETATTR || DEBUG_SIGNALS
 117 
 118 /* Async-safe implementation of sprintf (str, "%d", n).  */
 119 static _GL_ASYNC_SAFE void
 120 sprintf_integer (char *str, int x)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122   unsigned int y;
 123   char buf[20];
 124   char *p;
 125   size_t n;
 126 
 127   if (x < 0)
 128     {
 129       *str++ = '-';
 130       y = (unsigned int) (-1 - x) + 1;
 131     }
 132   else
 133     y = x;
 134 
 135   p = buf + sizeof (buf);
 136   do
 137     {
 138       *--p = '0' + (y % 10);
 139       y = y / 10;
 140     }
 141   while (y > 0);
 142   n = buf + sizeof (buf) - p;
 143   memcpy (str, p, n);
 144   str[n] = '\0';
 145 }
 146 
 147 #endif
 148 
 149 #if HAVE_TCGETATTR
 150 
 151 /* Async-safe conversion of errno value to string.  */
 152 static _GL_ASYNC_SAFE void
 153 simple_errno_string (char *str, int errnum)
     /* [previous][next][first][last][top][bottom][index][help] */
 154 {
 155   switch (errnum)
 156     {
 157     case EBADF:  strcpy (str, "EBADF"); break;
 158     case EINTR:  strcpy (str, "EINTR"); break;
 159     case EINVAL: strcpy (str, "EINVAL"); break;
 160     case EIO:    strcpy (str, "EIO"); break;
 161     case ENOTTY: strcpy (str, "ENOTTY"); break;
 162     default: sprintf_integer (str, errnum); break;
 163     }
 164 }
 165 
 166 #endif
 167 
 168 #if DEBUG_SIGNALS
 169 
 170 /* Async-safe conversion of signal number to name.  */
 171 static _GL_ASYNC_SAFE void
 172 simple_signal_string (char *str, int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 173 {
 174   switch (sig)
 175     {
 176     /* Fatal signals (see fatal-signal.c).  */
 177     #ifdef SIGINT
 178     case SIGINT:   strcpy (str, "SIGINT"); break;
 179     #endif
 180     #ifdef SIGTERM
 181     case SIGTERM:  strcpy (str, "SIGTERM"); break;
 182     #endif
 183     #ifdef SIGHUP
 184     case SIGHUP:   strcpy (str, "SIGHUP"); break;
 185     #endif
 186     #ifdef SIGPIPE
 187     case SIGPIPE:  strcpy (str, "SIGPIPE"); break;
 188     #endif
 189     #ifdef SIGXCPU
 190     case SIGXCPU:  strcpy (str, "SIGXCPU"); break;
 191     #endif
 192     #ifdef SIGXFSZ
 193     case SIGXFSZ:  strcpy (str, "SIGXFSZ"); break;
 194     #endif
 195     #ifdef SIGBREAK
 196     case SIGBREAK: strcpy (str, "SIGBREAK"); break;
 197     #endif
 198     /* Stopping signals.  */
 199     #ifdef SIGTSTP
 200     case SIGTSTP:  strcpy (str, "SIGTSTP"); break;
 201     #endif
 202     #ifdef SIGTTIN
 203     case SIGTTIN:  strcpy (str, "SIGTTIN"); break;
 204     #endif
 205     #ifdef SIGTTOU
 206     case SIGTTOU:  strcpy (str, "SIGTTOU"); break;
 207     #endif
 208     /* Continuing signals.  */
 209     #ifdef SIGCONT
 210     case SIGCONT:  strcpy (str, "SIGCONT"); break;
 211     #endif
 212     default: sprintf_integer (str, sig); break;
 213     }
 214 }
 215 
 216 /* Emit a message that a given signal handler is being run.  */
 217 static _GL_ASYNC_SAFE void
 218 log_signal_handler_called (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220   char message[100];
 221   strcpy (message, "Signal handler for signal ");
 222   simple_signal_string (message + strlen (message), sig);
 223   strcat (message, " called.\n");
 224   log_message (message);
 225 }
 226 
 227 #else
 228 
 229 # define log_signal_handler_called(sig)
 230 
 231 #endif
 232 
 233 
 234 /* ============================ Signal handling ============================ */
 235 
 236 /* There are several situations which can cause garbled output on the terminal's
 237    screen:
 238    (1) When the program calls exit() after calling flush_to_current_style,
 239        the program would terminate and leave the terminal in a non-default
 240        state.
 241    (2) When the program is interrupted through a fatal signal, the terminal
 242        would be left in a non-default state.
 243    (3) When the program is stopped through a stopping signal, the terminal
 244        would be left (for temporary use by other programs) in a non-default
 245        state.
 246    (4) When a foreground process receives a SIGINT, the kernel(!) prints '^C'.
 247        On Linux, the place where this happens is
 248          linux-5.0/drivers/tty/n_tty.c:713..730
 249        within a call sequence
 250          n_tty_receive_signal_char (n_tty.c:1245..1246)
 251          -> commit_echoes (n_tty.c:792)
 252          -> __process_echoes (n_tty.c:713..730).
 253    (5) When a signal is sent, the output buffer is cleared.
 254        On Linux, this output buffer consists of the "echo buffer" in the tty
 255        and the "output buffer" in the driver.  The place where this happens is
 256          linux-5.0/drivers/tty/n_tty.c:1133..1140
 257        within a call
 258          isig (n_tty.c:1133..1140).
 259 
 260    How do we mitigate these problems?
 261    (1) We install an exit handler that restores the terminal to the default
 262        state.
 263    (2) If tty_control is TTYCTL_PARTIAL or TTYCTL_FULL:
 264        For some of the fatal signals (see gnulib's 'fatal-signal' module for
 265        the precise list), we install a handler that attempts to restore the
 266        terminal to the default state.  Since the terminal may be in the middle
 267        of outputting an escape sequence at this point, the first escape
 268        sequence emitted from this handler may have no effect and produce
 269        garbled characters instead.  Therefore the handler outputs the cleanup
 270        sequence twice.
 271        For the other fatal signals, we don't do anything.
 272    (3) If tty_control is TTYCTL_PARTIAL or TTYCTL_FULL:
 273        For some of the stopping signals (SIGTSTP, SIGTTIN, SIGTTOU), we install
 274        a handler that attempts to restore the terminal to the default state.
 275        For SIGCONT, we install a handler that does the opposite: it puts the
 276        terminal into the desired state again.
 277        For SIGSTOP, we cannot do anything.
 278    (4) If tty_control is TTYCTL_FULL:
 279        The kernel's action depends on L_ECHO(tty) and L_ISIG(tty), that is, on
 280        the local modes of the tty (see
 281        <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
 282        section 11.2.5).  We don't want to change L_ISIG; hence we change L_ECHO.
 283        So, we disable the ECHO local flag of the tty; the equivalent command is
 284        'stty -echo'.
 285    (5) If tty_control is TTYCTL_FULL:
 286        The kernel's action depends on !L_NOFLSH(tty), that is, again on the
 287        local modes of the tty (see
 288        <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
 289        section 11.2.5).  So, we enable the NOFLSH local flag of the tty; the
 290        equivalent command is 'stty noflsh'.
 291        For terminals with a baud rate < 9600 this is suboptimal.  For this case
 292        - where the traditional flushing behaviour makes sense - we would use a
 293        technique that involves tcdrain(), TIOCOUTQ, and usleep() when it is OK
 294        to disable NOFLSH.
 295 
 296    Regarding (4) and (5), there is a complication: Changing the local modes is
 297    done through tcsetattr().  However, when the process is put into the
 298    background, tcsetattr() does not operate the same way as when the process is
 299    running in the foreground.
 300    To test this kind of behaviour, use the 'color-filter' example like this:
 301      $ yes | ./filter '.*'
 302      <Ctrl-Z>
 303      $ bg 1
 304    We have three possible implementation options:
 305      * If we don't ignore the signal SIGTTOU:
 306        If the TOSTOP bit in the terminal's local mode is clear (command
 307        equivalent: 'stty -tostop') and the process is put into the background,
 308        normal output would continue (per POSIX
 309        <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
 310        section 11.2.5) but tcsetattr() calls would cause it to stop due to
 311        a SIGTTOU signal (per POSIX
 312        <https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html>).
 313        Thus, the program would behave differently with term-style-control than
 314        without.
 315      * If we ignore the signal SIGTTOU when the TOSTOP bit in the terminal's
 316        local mode is clear (i.e. when (tc.c_lflag & TOSTOP) == 0):
 317        The tcsetattr() calls do not stop the process, but they don't have the
 318        desired effect.
 319        On Linux, when I put the process into the background and then kill it with
 320        signal SIGINT, I can see that the last operation on the terminal settings
 321        (as shown by 'strace') is
 322          ioctl(1, TCSETSW, {B38400 opost isig icanon echo ...}) = 0
 323        and yet, once the process is terminated, the terminal settings contain
 324        '-echo', not 'echo'.
 325      * Don't call tcsetattr() if the process is not in the foreground.
 326        This approach produces reliable results.
 327 
 328    Blocking some signals while a non-default style is active is *not* useful:
 329      - It does not help against (1), since exit() is not a signal.
 330      - Signal handlers are the better approach against (2) and (3).
 331      - It does not help against (4) and (5), because the kernel's actions happen
 332        outside the process.  */
 333 #define BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT 0
 334 
 335 /* File descriptor of the currently active 'struct term_style_controller' and
 336    'struct term_style_user_data'.  */
 337 static int volatile term_fd = -1;
 338 
 339 #if HAVE_TCGETATTR
 340 
 341 /* Status of the process group of term_fd.  */
 342 typedef enum
 343 {
 344   PGRP_UNKNOWN = 0,     /* term_fd < 0.  Unknown status.  */
 345   PGRP_NO_TTY,          /* term_fd >= 0 but is not connected to a tty.  */
 346   PGRP_IN_FOREGROUND,   /* term_fd >= 0 is a tty.  This process is running in
 347                            the foreground.  */
 348   PGRP_IN_BACKGROUND    /* term_fd >= 0 is a tty.  This process is running in
 349                            the background.  */
 350 } pgrp_status_t;
 351 static pgrp_status_t volatile pgrp_status = PGRP_UNKNOWN;
 352 
 353 /* Update pgrp_status, depending on term_fd.  */
 354 static _GL_ASYNC_SAFE void
 355 update_pgrp_status (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 356 {
 357   int fd = term_fd;
 358   if (fd < 0)
 359     {
 360       pgrp_status = PGRP_UNKNOWN;
 361       log_message ("pgrp_status = PGRP_UNKNOWN\n");
 362     }
 363   else
 364     {
 365       pid_t p = tcgetpgrp (fd);
 366       if (p < 0)
 367         {
 368           pgrp_status = PGRP_NO_TTY;
 369           log_message ("pgrp_status = PGRP_NO_TTY\n");
 370         }
 371       else
 372         {
 373           /* getpgrp () changes when the process gets put into the background
 374              by a shell that implements job control.  */
 375           if (p == getpgrp ())
 376             {
 377               pgrp_status = PGRP_IN_FOREGROUND;
 378               log_message ("pgrp_status = PGRP_IN_FOREGROUND\n");
 379             }
 380           else
 381             {
 382               pgrp_status = PGRP_IN_BACKGROUND;
 383               log_message ("pgrp_status = PGRP_IN_BACKGROUND\n");
 384             }
 385         }
 386     }
 387 }
 388 
 389 #else
 390 
 391 # define update_pgrp_status()
 392 
 393 #endif
 394 
 395 /* Controller and its user_data that contain information about how to do
 396    output.  */
 397 static const struct term_style_controller * volatile active_controller;
 398 static struct term_style_user_data * volatile active_user_data;
 399 
 400 /* The 'struct term_style_control_data' embedded in active_user_data.
 401    Same as
 402      (active_controller != NULL
 403       ? active_controller->get_control_data (active_user_data)
 404       : NULL).  */
 405 static struct term_style_control_data * volatile active_control_data;
 406 
 407 /* The fd contained in active_control_data.
 408    Same as
 409      (active_controller != NULL
 410       ? active_control_data->fd
 411       : -1).  */
 412 static int volatile active_fd = -1;
 413 
 414 /* The exit handler.  */
 415 static void
 416 atexit_handler (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 417 {
 418   /* Only do something while some output was started but not completed.  */
 419   if (active_controller != NULL)
 420     {
 421       active_controller->restore (active_user_data);
 422       deactivate_term_non_default_mode (active_controller, active_user_data);
 423       #if 0 /* not needed */
 424       deactivate_term_style_controller (active_controller, active_user_data);
 425       #endif
 426     }
 427 }
 428 
 429 #if HAVE_TCGETATTR
 430 
 431 /* Return a failure message after tcsetattr() failed.  */
 432 static _GL_ASYNC_SAFE void
 433 tcsetattr_failed (char message[100], const char *caller)
     /* [previous][next][first][last][top][bottom][index][help] */
 434 {
 435   int errnum = errno;
 436   strcpy (message, caller);
 437   strcat (message, ": tcsetattr(fd=");
 438   sprintf_integer (message + strlen (message), active_fd);
 439   strcat (message, ") failed, errno=");
 440   simple_errno_string (message + strlen (message), errnum);
 441   strcat (message, "\n");
 442 }
 443 
 444 /* True when orig_lflag represents the original tc.c_lflag.  */
 445 static bool volatile orig_lflag_set;
 446 static tcflag_t volatile orig_lflag;
 447 
 448 /* Modifies the tty's local mode, preparing for non-default terminal state.
 449    Used only when the active_control_data's tty_control is TTYCTL_FULL.  */
 450 static _GL_ASYNC_SAFE void
 451 clobber_local_mode (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 452 {
 453   /* Here, active_fd == term_fd.  */
 454   if (pgrp_status == PGRP_IN_FOREGROUND)
 455     {
 456       struct termios tc;
 457       if (nonintr_tcgetattr (active_fd, &tc) >= 0)
 458         {
 459           if (!orig_lflag_set)
 460             orig_lflag = tc.c_lflag;
 461           /* Set orig_lflag_set to true before actually modifying the tty's
 462              local mode, because restore_local_mode does nothing if
 463              orig_lflag_set is false.  */
 464           orig_lflag_set = true;
 465           tc.c_lflag &= ~ECHO;
 466           tc.c_lflag |= NOFLSH;
 467           if (nonintr_tcsetattr (active_fd, TCSANOW, &tc) < 0)
 468             {
 469               /* Since tcsetattr failed, restore_local_mode does not need to
 470                  restore anything.  Set orig_lflag_set to false to indicate
 471                  this.  */
 472               orig_lflag_set = false;
 473               {
 474                 char message[100];
 475                 tcsetattr_failed (message,
 476                                   "term-style-control:clobber_local_mode");
 477                 full_write (STDERR_FILENO, message, strlen (message));
 478               }
 479             }
 480         }
 481     }
 482 }
 483 
 484 /* Modifies the tty's local mode, once the terminal is back to the default state.
 485    Returns true if ECHO was turned off.
 486    Used only when the active_control_data's tty_control is TTYCTL_FULL.  */
 487 static _GL_ASYNC_SAFE bool
 488 restore_local_mode (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 489 {
 490   /* Here, active_fd == term_fd.  */
 491   bool echo_was_off = false;
 492   /* Nothing to do if !orig_lflag_set.  */
 493   if (orig_lflag_set)
 494     {
 495       struct termios tc;
 496       if (nonintr_tcgetattr (active_fd, &tc) >= 0)
 497         {
 498           echo_was_off = (tc.c_lflag & ECHO) == 0;
 499           tc.c_lflag = orig_lflag;
 500           if (nonintr_tcsetattr (active_fd, TCSADRAIN, &tc) < 0)
 501             {
 502               char message[100];
 503               tcsetattr_failed (message,
 504                                 "term-style-control:restore_local_mode");
 505               full_write (STDERR_FILENO, message, strlen (message));
 506             }
 507         }
 508       orig_lflag_set = false;
 509     }
 510   return echo_was_off;
 511 }
 512 
 513 #endif
 514 
 515 #if defined SIGCONT
 516 
 517 /* The list of signals whose default behaviour is to stop or continue the
 518    program.  */
 519 static int const job_control_signals[] =
 520   {
 521     #ifdef SIGTSTP
 522     SIGTSTP,
 523     #endif
 524     #ifdef SIGTTIN
 525     SIGTTIN,
 526     #endif
 527     #ifdef SIGTTOU
 528     SIGTTOU,
 529     #endif
 530     #ifdef SIGCONT
 531     SIGCONT,
 532     #endif
 533     0
 534   };
 535 
 536 # define num_job_control_signals (SIZEOF (job_control_signals) - 1)
 537 
 538 #endif
 539 
 540 /* The following signals are relevant because they output escape sequences to
 541    the terminal:
 542      - fatal signals,
 543      - stopping signals,
 544      - continuing signals (SIGCONT).  */
 545 
 546 static sigset_t relevant_signal_set;
 547 static bool relevant_signal_set_initialized = false;
 548 
 549 static void
 550 init_relevant_signal_set ()
     /* [previous][next][first][last][top][bottom][index][help] */
 551 {
 552   if (!relevant_signal_set_initialized)
 553     {
 554       int fatal_signals[64];
 555       size_t num_fatal_signals;
 556       size_t i;
 557 
 558       num_fatal_signals = get_fatal_signals (fatal_signals);
 559 
 560       sigemptyset (&relevant_signal_set);
 561       for (i = 0; i < num_fatal_signals; i++)
 562         sigaddset (&relevant_signal_set, fatal_signals[i]);
 563       #if defined SIGCONT
 564       for (i = 0; i < num_job_control_signals; i++)
 565         sigaddset (&relevant_signal_set, job_control_signals[i]);
 566       #endif
 567 
 568       relevant_signal_set_initialized = true;
 569     }
 570 }
 571 
 572 /* Temporarily delay the relevant signals.  */
 573 static _GL_ASYNC_SAFE inline void
 574 block_relevant_signals ()
     /* [previous][next][first][last][top][bottom][index][help] */
 575 {
 576   /* The caller must ensure that init_relevant_signal_set () was already
 577      called.  */
 578   if (!relevant_signal_set_initialized)
 579     abort ();
 580 
 581   sigprocmask (SIG_BLOCK, &relevant_signal_set, NULL);
 582 }
 583 
 584 /* Stop delaying the relevant signals.  */
 585 static _GL_ASYNC_SAFE inline void
 586 unblock_relevant_signals ()
     /* [previous][next][first][last][top][bottom][index][help] */
 587 {
 588   sigprocmask (SIG_UNBLOCK, &relevant_signal_set, NULL);
 589 }
 590 
 591 #if defined SIGCONT
 592 
 593 /* Determines whether a signal is ignored.  */
 594 static _GL_ASYNC_SAFE bool
 595 is_ignored (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 596 {
 597   struct sigaction action;
 598 
 599   return (sigaction (sig, NULL, &action) >= 0
 600           && get_handler (&action) == SIG_IGN);
 601 }
 602 
 603 #endif
 604 
 605 #if HAVE_TCGETATTR
 606 
 607 /* Write the same signal marker that the kernel would have printed if ECHO had
 608    been turned on.  See (4) above.
 609    This is a makeshift and is not perfect:
 610      - When stderr refers to a different target than active_control_data->fd,
 611        it is too hairy to write the signal marker.
 612      - In some cases, when the signal was generated right before and delivered
 613        right after a clobber_local_mode invocation, the result is that the
 614        marker appears twice, e.g. ^C^C.  This occurs only with a small
 615        probability.
 616      - In some cases, when the signal was generated right before and delivered
 617        right after a restore_local_mode invocation, the result is that the
 618        marker does not appear at all.  This occurs only with a small
 619        probability.
 620    To test this kind of behaviour, use the 'test-term-style-control-yes' example
 621    like this:
 622      $ ./test-term-style-control-yes
 623  */
 624 static _GL_ASYNC_SAFE void
 625 show_signal_marker (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 626 {
 627   /* Write to stderr, not to active_control_data->fd, because
 628      active_control_data->fd is often logged or used with 'less -R'.  */
 629   if (active_controller != NULL && active_control_data->same_as_stderr)
 630     switch (sig)
 631       {
 632       /* The kernel's action when the user presses the INTR key.  */
 633       case SIGINT:
 634         full_write (STDERR_FILENO, "^C", 2); break;
 635       /* The kernel's action when the user presses the SUSP key.  */
 636       case SIGTSTP:
 637         full_write (STDERR_FILENO, "^Z", 2); break;
 638       /* The kernel's action when the user presses the QUIT key.  */
 639       case SIGQUIT:
 640         full_write (STDERR_FILENO, "^\\", 2); break;
 641       default: break;
 642       }
 643 }
 644 
 645 #endif
 646 
 647 /* The main code of the signal handler for fatal signals and stopping signals.
 648    It is reentrant.  */
 649 static _GL_ASYNC_SAFE void
 650 fatal_or_stopping_signal_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 651 {
 652   #if HAVE_TCGETATTR
 653   bool echo_was_off = false;
 654   #endif
 655   /* Only do something while some output was interrupted.  */
 656   if (active_controller != NULL
 657       && active_control_data->tty_control != TTYCTL_NONE)
 658     {
 659       unsigned int i;
 660 
 661       /* Block the relevant signals.  This is needed, because the output
 662          of escape sequences below (usually through tputs invocations) is
 663          not reentrant.  */
 664       block_relevant_signals ();
 665 
 666       /* Restore the terminal to the default state.  */
 667       for (i = 0; i < 2; i++)
 668         active_controller->async_restore (active_user_data);
 669       #if HAVE_TCGETATTR
 670       if (active_control_data->tty_control == TTYCTL_FULL)
 671         {
 672           /* Restore the local mode, once the escape sequences output above
 673              have reached their destination.  */
 674           echo_was_off = restore_local_mode ();
 675         }
 676       #endif
 677 
 678       /* Unblock the relevant signals.  */
 679       unblock_relevant_signals ();
 680     }
 681 
 682   #if HAVE_TCGETATTR
 683   if (echo_was_off)
 684     show_signal_marker (sig);
 685   #endif
 686 }
 687 
 688 /* The signal handler for fatal signals.
 689    It is reentrant.  */
 690 static _GL_ASYNC_SAFE void
 691 fatal_signal_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 692 {
 693   log_signal_handler_called (sig);
 694   fatal_or_stopping_signal_handler (sig);
 695 }
 696 
 697 #if defined SIGCONT
 698 
 699 /* The signal handler for stopping signals.
 700    It is reentrant.  */
 701 static _GL_ASYNC_SAFE void
 702 stopping_signal_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 703 {
 704   int saved_errno = errno;
 705 
 706   log_signal_handler_called (sig);
 707   fatal_or_stopping_signal_handler (sig);
 708 
 709   /* Now execute the signal's default action.
 710      We reinstall the handler later, during the SIGCONT handler.  */
 711   {
 712     struct sigaction action;
 713     action.sa_handler = SIG_DFL;
 714     action.sa_flags = SA_NODEFER;
 715     sigemptyset (&action.sa_mask);
 716     sigaction (sig, &action, NULL);
 717   }
 718   errno = saved_errno;
 719   raise (sig);
 720 }
 721 
 722 /* The signal handler for SIGCONT.
 723    It is reentrant.  */
 724 static _GL_ASYNC_SAFE void
 725 continuing_signal_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 726 {
 727   int saved_errno = errno;
 728 
 729   log_signal_handler_called (sig);
 730   update_pgrp_status ();
 731   /* Only do something while some output was interrupted.  */
 732   if (active_controller != NULL
 733       && active_control_data->tty_control != TTYCTL_NONE)
 734     {
 735       /* Reinstall the signals handlers removed in stopping_signal_handler.  */
 736       {
 737         unsigned int i;
 738 
 739         for (i = 0; i < num_job_control_signals; i++)
 740           {
 741             int sig = job_control_signals[i];
 742 
 743             if (sig != SIGCONT && !is_ignored (sig))
 744               {
 745                 struct sigaction action;
 746                 action.sa_handler = &stopping_signal_handler;
 747                 /* If we get a stopping or continuing signal while executing
 748                    stopping_signal_handler or continuing_signal_handler, enter
 749                    it recursively, since it is reentrant.
 750                    Hence no SA_RESETHAND.  */
 751                 action.sa_flags = SA_NODEFER;
 752                 sigemptyset (&action.sa_mask);
 753                 sigaction (sig, &action, NULL);
 754               }
 755           }
 756       }
 757 
 758       /* Block the relevant signals.  This is needed, because the output of
 759          escape sequences done inside the async_set_attributes_from_default
 760          call below is not reentrant.  */
 761       block_relevant_signals ();
 762 
 763       #if HAVE_TCGETATTR
 764       if (active_control_data->tty_control == TTYCTL_FULL)
 765         {
 766           /* Modify the local mode.  */
 767           clobber_local_mode ();
 768         }
 769       #endif
 770       /* Set the terminal attributes.  */
 771       active_controller->async_set_attributes_from_default (active_user_data);
 772 
 773       /* Unblock the relevant signals.  */
 774       unblock_relevant_signals ();
 775     }
 776 
 777   errno = saved_errno;
 778 }
 779 
 780 /* Ensure the signal handlers are installed.
 781    Once they are installed, we leave them installed.  It's not worth
 782    installing and uninstalling them each time we switch the terminal to a
 783    non-default state and back; instead we set active_controller to tell the
 784    signal handler whether it has something to do or not.  */
 785 
 786 static void
 787 ensure_continuing_signal_handler (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 788 {
 789   static bool signal_handler_installed = false;
 790 
 791   if (!signal_handler_installed)
 792     {
 793       int sig = SIGCONT;
 794       struct sigaction action;
 795       action.sa_handler = &continuing_signal_handler;
 796       /* If we get a stopping or continuing signal while executing
 797          continuing_signal_handler, enter it recursively, since it is
 798          reentrant.  Hence no SA_RESETHAND.  */
 799       action.sa_flags = SA_NODEFER;
 800       sigemptyset (&action.sa_mask);
 801       sigaction (sig, &action, NULL);
 802 
 803       signal_handler_installed = true;
 804     }
 805 }
 806 
 807 #endif
 808 
 809 static void
 810 ensure_other_signal_handlers (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 811 {
 812   static bool signal_handlers_installed = false;
 813 
 814   if (!signal_handlers_installed)
 815     {
 816       /* Install the handlers for the fatal signals.  */
 817       if (at_fatal_signal (fatal_signal_handler) < 0)
 818         xalloc_die ();
 819 
 820       #if defined SIGCONT
 821 
 822       /* Install the handlers for the stopping and continuing signals.  */
 823       {
 824         unsigned int i;
 825 
 826         for (i = 0; i < num_job_control_signals; i++)
 827           {
 828             int sig = job_control_signals[i];
 829 
 830             if (sig == SIGCONT)
 831               /* Already handled in ensure_continuing_signal_handler.  */
 832               ;
 833             else if (!is_ignored (sig))
 834               {
 835                 struct sigaction action;
 836                 action.sa_handler = &stopping_signal_handler;
 837                 /* If we get a stopping or continuing signal while executing
 838                    stopping_signal_handler, enter it recursively, since it is
 839                    reentrant.  Hence no SA_RESETHAND.  */
 840                 action.sa_flags = SA_NODEFER;
 841                 sigemptyset (&action.sa_mask);
 842                 sigaction (sig, &action, NULL);
 843               }
 844             #if DEBUG_SIGNALS
 845             else
 846               {
 847                 fprintf (stderr, "Signal %d is ignored. Not installing a handler!\n",
 848                          sig);
 849                 fflush (stderr);
 850               }
 851             #endif
 852           }
 853       }
 854 
 855       #endif
 856 
 857       signal_handlers_installed = true;
 858     }
 859 }
 860 
 861 
 862 /* ============================== Public API ============================== */
 863 
 864 void
 865 activate_term_non_default_mode (const struct term_style_controller *controller,
     /* [previous][next][first][last][top][bottom][index][help] */
 866                                 struct term_style_user_data *user_data)
 867 {
 868   struct term_style_control_data *control_data =
 869     controller->get_control_data (user_data);
 870 
 871   if (!control_data->non_default_active)
 872     {
 873       if (control_data->tty_control != TTYCTL_NONE)
 874         ensure_other_signal_handlers ();
 875 
 876       #if BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT
 877       /* Block fatal signals, so that a SIGINT or similar doesn't interrupt
 878          us without the possibility of restoring the terminal's state.
 879          Likewise for SIGTSTP etc.  */
 880       block_relevant_signals ();
 881       #endif
 882 
 883       /* Enable the exit handler for restoring the terminal's state,
 884          and make the signal handlers effective.  */
 885       if (active_controller != NULL)
 886         {
 887           /* We can't support two active controllers with non-default
 888              attributes at the same time.  */
 889           abort ();
 890         }
 891       /* The uses of 'volatile' (and ISO C 99 section 5.1.2.3.(5)) ensure that
 892          we set active_controller to a non-NULL value only after the memory
 893          locations active_user_data, active_control_data, active_fd have been
 894          filled.  */
 895       active_fd = control_data->fd;
 896       active_control_data = control_data;
 897       active_user_data = user_data;
 898       active_controller = controller;
 899 
 900       #if HAVE_TCGETATTR
 901       /* Now that the signal handlers are effective, modify the tty.  */
 902       if (active_control_data->tty_control == TTYCTL_FULL)
 903         {
 904           /* Modify the local mode.  */
 905           clobber_local_mode ();
 906         }
 907       #endif
 908 
 909       control_data->non_default_active = true;
 910     }
 911 }
 912 
 913 void
 914 deactivate_term_non_default_mode (const struct term_style_controller *controller,
     /* [previous][next][first][last][top][bottom][index][help] */
 915                                   struct term_style_user_data *user_data)
 916 {
 917   struct term_style_control_data *control_data =
 918     controller->get_control_data (user_data);
 919 
 920   if (control_data->non_default_active)
 921     {
 922       #if HAVE_TCGETATTR
 923       /* Before we make the signal handlers ineffective, modify the tty.  */
 924       if (active_control_data->tty_control == TTYCTL_FULL)
 925         {
 926           /* Restore the local mode, once the tputs calls from out_attr_change
 927              have reached their destination.  */
 928           restore_local_mode ();
 929         }
 930       #endif
 931 
 932       /* Disable the exit handler, and make the signal handlers ineffective.  */
 933       /* The uses of 'volatile' (and ISO C 99 section 5.1.2.3.(5)) ensure that
 934          we reset active_user_data, active_control_data, active_fd only after
 935          the memory location active_controller has been cleared.  */
 936       active_controller = NULL;
 937       active_user_data = NULL;
 938       active_control_data = NULL;
 939       active_fd = -1;
 940 
 941       #if BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT
 942       /* Unblock the relevant signals.  */
 943       unblock_relevant_signals ();
 944       #endif
 945 
 946       control_data->non_default_active = false;
 947     }
 948 }
 949 
 950 void
 951 activate_term_style_controller (const struct term_style_controller *controller,
     /* [previous][next][first][last][top][bottom][index][help] */
 952                                 struct term_style_user_data *user_data,
 953                                 int fd, ttyctl_t tty_control)
 954 {
 955   struct term_style_control_data *control_data =
 956     controller->get_control_data (user_data);
 957 
 958   control_data->fd = fd;
 959 
 960   /* Prepare tty control.  */
 961   if (tty_control == TTYCTL_AUTO)
 962     tty_control = TTYCTL_FULL;
 963   control_data->tty_control = tty_control;
 964   if (control_data->tty_control != TTYCTL_NONE)
 965     init_relevant_signal_set ();
 966   #if HAVE_TCGETATTR
 967   if (control_data->tty_control == TTYCTL_FULL)
 968     {
 969       struct stat statbuf1;
 970       struct stat statbuf2;
 971       if (fd == STDERR_FILENO
 972           || (fstat (fd, &statbuf1) >= 0
 973               && fstat (STDERR_FILENO, &statbuf2) >= 0
 974               && SAME_INODE (statbuf1, statbuf2)))
 975         control_data->same_as_stderr = true;
 976       else
 977         control_data->same_as_stderr = false;
 978     }
 979   else
 980     /* This value is actually not used.  */
 981     control_data->same_as_stderr = false;
 982   #endif
 983 
 984   control_data->non_default_active = false;
 985 
 986   /* Start keeping track of the process group status.  */
 987   term_fd = fd;
 988   #if defined SIGCONT
 989   ensure_continuing_signal_handler ();
 990   #endif
 991   update_pgrp_status ();
 992 
 993   /* Register an exit handler.  */
 994   {
 995     static bool registered = false;
 996     if (!registered)
 997       {
 998         atexit (atexit_handler);
 999         registered = true;
1000       }
1001   }
1002 }
1003 
1004 void
1005 deactivate_term_style_controller (const struct term_style_controller *controller,
     /* [previous][next][first][last][top][bottom][index][help] */
1006                                   struct term_style_user_data *user_data)
1007 {
1008   struct term_style_control_data *control_data =
1009     controller->get_control_data (user_data);
1010 
1011   /* Verify that the non-default attributes mode is turned off.  */
1012   if (control_data->non_default_active)
1013     abort ();
1014 
1015   term_fd = -1;
1016   update_pgrp_status ();
1017 }

/* [previous][next][first][last][top][bottom][index][help] */