mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-01 21:33:04 +00:00
296 lines
8.2 KiB
C
296 lines
8.2 KiB
C
/* signals.c -- install and maintain signal handlers.
|
|
$Id: signals.c,v 1.7 2004/04/11 17:56:46 karl Exp $
|
|
|
|
Copyright (C) 1993, 1994, 1995, 1998, 2002, 2003, 2004 Free Software
|
|
Foundation, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
Originally written by Brian Fox (bfox@ai.mit.edu). */
|
|
|
|
#include "info.h"
|
|
#include "signals.h"
|
|
|
|
void initialize_info_signal_handler (void);
|
|
|
|
/* **************************************************************** */
|
|
/* */
|
|
/* Pretending That We Have POSIX Signals */
|
|
/* */
|
|
/* **************************************************************** */
|
|
|
|
#if !defined (HAVE_SIGPROCMASK) && defined (HAVE_SIGSETMASK)
|
|
/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
|
|
static void
|
|
sigprocmask (int operation, int *newset, int *oldset)
|
|
{
|
|
switch (operation)
|
|
{
|
|
case SIG_UNBLOCK:
|
|
sigsetmask (sigblock (0) & ~(*newset));
|
|
break;
|
|
|
|
case SIG_BLOCK:
|
|
*oldset = sigblock (*newset);
|
|
break;
|
|
|
|
case SIG_SETMASK:
|
|
sigsetmask (*newset);
|
|
break;
|
|
|
|
default:
|
|
abort ();
|
|
}
|
|
}
|
|
#endif /* !HAVE_SIGPROCMASK && HAVE_SIGSETMASK */
|
|
|
|
/* **************************************************************** */
|
|
/* */
|
|
/* Signal Handling for Info */
|
|
/* */
|
|
/* **************************************************************** */
|
|
|
|
#if defined (HAVE_SIGACTION) || defined (HAVE_SIGPROCMASK) ||\
|
|
defined (HAVE_SIGSETMASK)
|
|
static void
|
|
mask_termsig (sigset_t *set)
|
|
{
|
|
# if defined (SIGTSTP)
|
|
sigaddset (set, SIGTSTP);
|
|
sigaddset (set, SIGTTOU);
|
|
sigaddset (set, SIGTTIN);
|
|
# endif
|
|
# if defined (SIGWINCH)
|
|
sigaddset (set, SIGWINCH);
|
|
# endif
|
|
#if defined (SIGQUIT)
|
|
sigaddset (set, SIGQUIT);
|
|
#endif
|
|
#if defined (SIGINT)
|
|
sigaddset (set, SIGINT);
|
|
#endif
|
|
# if defined (SIGUSR1)
|
|
sigaddset (set, SIGUSR1);
|
|
# endif
|
|
}
|
|
#endif /* HAVE_SIGACTION || HAVE_SIGPROCMASK || HAVE_SIGSETMASK */
|
|
|
|
static RETSIGTYPE info_signal_proc (int sig);
|
|
#if defined (HAVE_SIGACTION)
|
|
typedef struct sigaction signal_info;
|
|
signal_info info_signal_handler;
|
|
|
|
static void
|
|
set_termsig (int sig, signal_info *old)
|
|
{
|
|
sigaction (sig, &info_signal_handler, old);
|
|
}
|
|
|
|
static void
|
|
restore_termsig (int sig, const signal_info *saved)
|
|
{
|
|
sigaction (sig, saved, NULL);
|
|
}
|
|
#else /* !HAVE_SIGACTION */
|
|
typedef RETSIGTYPE (*signal_info) ();
|
|
#define set_termsig(sig, old) (void)(*(old) = signal (sig, info_signal_proc))
|
|
#define restore_termsig(sig, saved) (void)signal (sig, *(saved))
|
|
#define info_signal_handler info_signal_proc
|
|
static int term_conf_busy = 0;
|
|
#endif /* !HAVE_SIGACTION */
|
|
|
|
static signal_info old_TSTP, old_TTOU, old_TTIN;
|
|
static signal_info old_WINCH, old_INT, old_USR1;
|
|
static signal_info old_QUIT;
|
|
|
|
void
|
|
initialize_info_signal_handler (void)
|
|
{
|
|
#ifdef SA_NOCLDSTOP
|
|
/* (Based on info from Paul Eggert found in coreutils.) Don't use
|
|
HAVE_SIGACTION to decide whether to use the sa_handler, sa_flags,
|
|
sa_mask members, as some systems (Solaris 7+) don't define them. Use
|
|
SA_NOCLDSTOP instead; it's been part of POSIX.1 since day 1 (in 1988). */
|
|
info_signal_handler.sa_handler = info_signal_proc;
|
|
info_signal_handler.sa_flags = 0;
|
|
mask_termsig (&info_signal_handler.sa_mask);
|
|
#endif /* SA_NOCLDSTOP */
|
|
|
|
#if defined (SIGTSTP)
|
|
set_termsig (SIGTSTP, &old_TSTP);
|
|
set_termsig (SIGTTOU, &old_TTOU);
|
|
set_termsig (SIGTTIN, &old_TTIN);
|
|
#endif /* SIGTSTP */
|
|
|
|
#if defined (SIGWINCH)
|
|
set_termsig (SIGWINCH, &old_WINCH);
|
|
#endif
|
|
|
|
#if defined (SIGQUIT)
|
|
set_termsig (SIGQUIT, &old_QUIT);
|
|
#endif
|
|
|
|
#if defined (SIGINT)
|
|
set_termsig (SIGINT, &old_INT);
|
|
#endif
|
|
|
|
#if defined (SIGUSR1)
|
|
/* Used by DJGPP to simulate SIGTSTP on Ctrl-Z. */
|
|
set_termsig (SIGUSR1, &old_USR1);
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
redisplay_after_signal (void)
|
|
{
|
|
terminal_clear_screen ();
|
|
display_clear_display (the_display);
|
|
window_mark_chain (windows, W_UpdateWindow);
|
|
display_update_display (windows);
|
|
display_cursor_at_point (active_window);
|
|
fflush (stdout);
|
|
}
|
|
|
|
static void
|
|
reset_info_window_sizes (void)
|
|
{
|
|
terminal_goto_xy (0, 0);
|
|
fflush (stdout);
|
|
terminal_unprep_terminal ();
|
|
terminal_get_screen_size ();
|
|
terminal_prep_terminal ();
|
|
display_initialize_display (screenwidth, screenheight);
|
|
window_new_screen_size (screenwidth, screenheight);
|
|
redisplay_after_signal ();
|
|
}
|
|
|
|
static RETSIGTYPE
|
|
info_signal_proc (int sig)
|
|
{
|
|
signal_info *old_signal_handler = NULL;
|
|
|
|
#if !defined (HAVE_SIGACTION)
|
|
/* best effort: first increment this counter and later block signals */
|
|
if (term_conf_busy)
|
|
return;
|
|
term_conf_busy++;
|
|
#if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK)
|
|
{
|
|
sigset_t nvar, ovar;
|
|
sigemptyset (&nvar);
|
|
mask_termsig (&nvar);
|
|
sigprocmask (SIG_BLOCK, &nvar, &ovar);
|
|
}
|
|
#endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */
|
|
#endif /* !HAVE_SIGACTION */
|
|
switch (sig)
|
|
{
|
|
#if defined (SIGTSTP)
|
|
case SIGTSTP:
|
|
case SIGTTOU:
|
|
case SIGTTIN:
|
|
#endif
|
|
#if defined (SIGQUIT)
|
|
case SIGQUIT:
|
|
#endif
|
|
#if defined (SIGINT)
|
|
case SIGINT:
|
|
#endif
|
|
{
|
|
#if defined (SIGTSTP)
|
|
if (sig == SIGTSTP)
|
|
old_signal_handler = &old_TSTP;
|
|
if (sig == SIGTTOU)
|
|
old_signal_handler = &old_TTOU;
|
|
if (sig == SIGTTIN)
|
|
old_signal_handler = &old_TTIN;
|
|
#endif /* SIGTSTP */
|
|
#if defined (SIGQUIT)
|
|
if (sig == SIGQUIT)
|
|
old_signal_handler = &old_QUIT;
|
|
#endif /* SIGQUIT */
|
|
#if defined (SIGINT)
|
|
if (sig == SIGINT)
|
|
old_signal_handler = &old_INT;
|
|
#endif /* SIGINT */
|
|
|
|
/* For stop signals, restore the terminal IO, leave the cursor
|
|
at the bottom of the window, and stop us. */
|
|
terminal_goto_xy (0, screenheight - 1);
|
|
terminal_clear_to_eol ();
|
|
fflush (stdout);
|
|
terminal_unprep_terminal ();
|
|
restore_termsig (sig, old_signal_handler);
|
|
UNBLOCK_SIGNAL (sig);
|
|
kill (getpid (), sig);
|
|
|
|
/* The program is returning now. Restore our signal handler,
|
|
turn on terminal handling, redraw the screen, and place the
|
|
cursor where it belongs. */
|
|
terminal_prep_terminal ();
|
|
set_termsig (sig, old_signal_handler);
|
|
/* window size might be changed while sleeping */
|
|
reset_info_window_sizes ();
|
|
}
|
|
break;
|
|
|
|
#if defined (SIGWINCH) || defined (SIGUSR1)
|
|
#ifdef SIGWINCH
|
|
case SIGWINCH:
|
|
#endif
|
|
#ifdef SIGUSR1
|
|
case SIGUSR1:
|
|
#endif
|
|
{
|
|
/* Turn off terminal IO, tell our parent that the window has changed,
|
|
then reinitialize the terminal and rebuild our windows. */
|
|
#ifdef SIGWINCH
|
|
if (sig == SIGWINCH)
|
|
old_signal_handler = &old_WINCH;
|
|
#endif
|
|
#ifdef SIGUSR1
|
|
if (sig == SIGUSR1)
|
|
old_signal_handler = &old_USR1;
|
|
#endif
|
|
terminal_goto_xy (0, 0);
|
|
fflush (stdout);
|
|
terminal_unprep_terminal (); /* needless? */
|
|
restore_termsig (sig, old_signal_handler);
|
|
UNBLOCK_SIGNAL (sig);
|
|
kill (getpid (), sig);
|
|
|
|
/* After our old signal handler returns... */
|
|
set_termsig (sig, old_signal_handler); /* needless? */
|
|
terminal_prep_terminal ();
|
|
reset_info_window_sizes ();
|
|
}
|
|
break;
|
|
#endif /* SIGWINCH || SIGUSR1 */
|
|
}
|
|
#if !defined (HAVE_SIGACTION)
|
|
/* at this time it is safer to perform unblock after decrement */
|
|
term_conf_busy--;
|
|
#if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK)
|
|
{
|
|
sigset_t nvar, ovar;
|
|
sigemptyset (&nvar);
|
|
mask_termsig (&nvar);
|
|
sigprocmask (SIG_UNBLOCK, &nvar, &ovar);
|
|
}
|
|
#endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */
|
|
#endif /* !HAVE_SIGACTION */
|
|
}
|
|
/* vim: set sw=2 cino={1s>2sn-s^-se-s: */
|