signals.c revision 136644
1/* signals.c -- signal handling support for readline. */
2
3/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
4
5   This file is part of the GNU Readline Library, a library for
6   reading lines of text with interactive input and history editing.
7
8   The GNU Readline Library is free software; you can redistribute it
9   and/or modify it under the terms of the GNU General Public License
10   as published by the Free Software Foundation; either version 2, or
11   (at your option) any later version.
12
13   The GNU Readline Library is distributed in the hope that it will be
14   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   The GNU General Public License is often shipped with GNU software, and
19   is generally kept in a file called COPYING or LICENSE.  If you do not
20   have a copy of the license, write to the Free Software Foundation,
21   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
22#define READLINE_LIBRARY
23
24#if defined (HAVE_CONFIG_H)
25#  include <config.h>
26#endif
27
28#include <stdio.h>		/* Just for NULL.  Yuck. */
29#include <sys/types.h>
30#include <signal.h>
31
32#if defined (HAVE_UNISTD_H)
33#  include <unistd.h>
34#endif /* HAVE_UNISTD_H */
35
36/* System-specific feature definitions and include files. */
37#include "rldefs.h"
38
39#if defined (GWINSZ_IN_SYS_IOCTL)
40#  include <sys/ioctl.h>
41#endif /* GWINSZ_IN_SYS_IOCTL */
42
43#if defined (HANDLE_SIGNALS)
44/* Some standard library routines. */
45#include "readline.h"
46#include "history.h"
47
48#include "rlprivate.h"
49
50#if !defined (RETSIGTYPE)
51#  if defined (VOID_SIGHANDLER)
52#    define RETSIGTYPE void
53#  else
54#    define RETSIGTYPE int
55#  endif /* !VOID_SIGHANDLER */
56#endif /* !RETSIGTYPE */
57
58#if defined (VOID_SIGHANDLER)
59#  define SIGHANDLER_RETURN return
60#else
61#  define SIGHANDLER_RETURN return (0)
62#endif
63
64/* This typedef is equivalent to the one for Function; it allows us
65   to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
66typedef RETSIGTYPE SigHandler ();
67
68#if defined (HAVE_POSIX_SIGNALS)
69typedef struct sigaction sighandler_cxt;
70#  define rl_sigaction(s, nh, oh)	sigaction(s, nh, oh)
71#else
72typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt;
73#  define sigemptyset(m)
74#endif /* !HAVE_POSIX_SIGNALS */
75
76#ifndef SA_RESTART
77#  define SA_RESTART 0
78#endif
79
80static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *));
81static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *));
82
83/* Exported variables for use by applications. */
84
85/* If non-zero, readline will install its own signal handlers for
86   SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */
87int rl_catch_signals = 1;
88
89/* If non-zero, readline will install a signal handler for SIGWINCH. */
90#ifdef SIGWINCH
91int rl_catch_sigwinch = 1;
92#else
93int rl_catch_sigwinch = 0;	/* for the readline state struct in readline.c */
94#endif
95
96static int signals_set_flag;
97static int sigwinch_set_flag;
98
99/* **************************************************************** */
100/*					        		    */
101/*			   Signal Handling                          */
102/*								    */
103/* **************************************************************** */
104
105static sighandler_cxt old_int, old_term, old_alrm, old_quit;
106#if defined (SIGTSTP)
107static sighandler_cxt old_tstp, old_ttou, old_ttin;
108#endif
109#if defined (SIGWINCH)
110static sighandler_cxt old_winch;
111#endif
112
113/* Readline signal handler functions. */
114
115static RETSIGTYPE
116rl_signal_handler (sig)
117     int sig;
118{
119#if defined (HAVE_POSIX_SIGNALS)
120  sigset_t set;
121#else /* !HAVE_POSIX_SIGNALS */
122#  if defined (HAVE_BSD_SIGNALS)
123  long omask;
124#  else /* !HAVE_BSD_SIGNALS */
125  sighandler_cxt dummy_cxt;	/* needed for rl_set_sighandler call */
126#  endif /* !HAVE_BSD_SIGNALS */
127#endif /* !HAVE_POSIX_SIGNALS */
128
129  RL_SETSTATE(RL_STATE_SIGHANDLER);
130
131#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS)
132  /* Since the signal will not be blocked while we are in the signal
133     handler, ignore it until rl_clear_signals resets the catcher. */
134  if (sig == SIGINT || sig == SIGALRM)
135    rl_set_sighandler (sig, SIG_IGN, &dummy_cxt);
136#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */
137
138  switch (sig)
139    {
140    case SIGINT:
141      rl_free_line_state ();
142      /* FALLTHROUGH */
143
144#if defined (SIGTSTP)
145    case SIGTSTP:
146    case SIGTTOU:
147    case SIGTTIN:
148#endif /* SIGTSTP */
149    case SIGALRM:
150    case SIGTERM:
151    case SIGQUIT:
152      rl_cleanup_after_signal ();
153
154#if defined (HAVE_POSIX_SIGNALS)
155      sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set);
156      sigdelset (&set, sig);
157#else /* !HAVE_POSIX_SIGNALS */
158#  if defined (HAVE_BSD_SIGNALS)
159      omask = sigblock (0);
160#  endif /* HAVE_BSD_SIGNALS */
161#endif /* !HAVE_POSIX_SIGNALS */
162
163#if defined (__EMX__)
164      signal (sig, SIG_ACK);
165#endif
166
167      kill (getpid (), sig);
168
169      /* Let the signal that we just sent through.  */
170#if defined (HAVE_POSIX_SIGNALS)
171      sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL);
172#else /* !HAVE_POSIX_SIGNALS */
173#  if defined (HAVE_BSD_SIGNALS)
174      sigsetmask (omask & ~(sigmask (sig)));
175#  endif /* HAVE_BSD_SIGNALS */
176#endif /* !HAVE_POSIX_SIGNALS */
177
178      rl_reset_after_signal ();
179    }
180
181  RL_UNSETSTATE(RL_STATE_SIGHANDLER);
182  SIGHANDLER_RETURN;
183}
184
185#if defined (SIGWINCH)
186static RETSIGTYPE
187rl_sigwinch_handler (sig)
188     int sig;
189{
190  SigHandler *oh;
191
192#if defined (MUST_REINSTALL_SIGHANDLERS)
193  sighandler_cxt dummy_winch;
194
195  /* We don't want to change old_winch -- it holds the state of SIGWINCH
196     disposition set by the calling application.  We need this state
197     because we call the application's SIGWINCH handler after updating
198     our own idea of the screen size. */
199  rl_set_sighandler (SIGWINCH, rl_sigwinch_handler, &dummy_winch);
200#endif
201
202  RL_SETSTATE(RL_STATE_SIGHANDLER);
203  rl_resize_terminal ();
204
205  /* If another sigwinch handler has been installed, call it. */
206  oh = (SigHandler *)old_winch.sa_handler;
207  if (oh &&  oh != (SigHandler *)SIG_IGN && oh != (SigHandler *)SIG_DFL)
208    (*oh) (sig);
209
210  RL_UNSETSTATE(RL_STATE_SIGHANDLER);
211  SIGHANDLER_RETURN;
212}
213#endif  /* SIGWINCH */
214
215/* Functions to manage signal handling. */
216
217#if !defined (HAVE_POSIX_SIGNALS)
218static int
219rl_sigaction (sig, nh, oh)
220     int sig;
221     sighandler_cxt *nh, *oh;
222{
223  oh->sa_handler = signal (sig, nh->sa_handler);
224  return 0;
225}
226#endif /* !HAVE_POSIX_SIGNALS */
227
228/* Set up a readline-specific signal handler, saving the old signal
229   information in OHANDLER.  Return the old signal handler, like
230   signal(). */
231static SigHandler *
232rl_set_sighandler (sig, handler, ohandler)
233     int sig;
234     SigHandler *handler;
235     sighandler_cxt *ohandler;
236{
237  sighandler_cxt old_handler;
238#if defined (HAVE_POSIX_SIGNALS)
239  struct sigaction act;
240
241  act.sa_handler = handler;
242  act.sa_flags = (sig == SIGWINCH) ? SA_RESTART : 0;
243  sigemptyset (&act.sa_mask);
244  sigemptyset (&ohandler->sa_mask);
245  sigaction (sig, &act, &old_handler);
246#else
247  old_handler.sa_handler = (SigHandler *)signal (sig, handler);
248#endif /* !HAVE_POSIX_SIGNALS */
249
250  /* XXX -- assume we have memcpy */
251  /* If rl_set_signals is called twice in a row, don't set the old handler to
252     rl_signal_handler, because that would cause infinite recursion. */
253  if (handler != rl_signal_handler || old_handler.sa_handler != rl_signal_handler)
254    memcpy (ohandler, &old_handler, sizeof (sighandler_cxt));
255
256  return (ohandler->sa_handler);
257}
258
259static void
260rl_maybe_set_sighandler (sig, handler, ohandler)
261     int sig;
262     SigHandler *handler;
263     sighandler_cxt *ohandler;
264{
265  sighandler_cxt dummy;
266  SigHandler *oh;
267
268  sigemptyset (&dummy.sa_mask);
269  oh = rl_set_sighandler (sig, handler, ohandler);
270  if (oh == (SigHandler *)SIG_IGN)
271    rl_sigaction (sig, ohandler, &dummy);
272}
273
274int
275rl_set_signals ()
276{
277  sighandler_cxt dummy;
278  SigHandler *oh;
279
280  if (rl_catch_signals && signals_set_flag == 0)
281    {
282      rl_maybe_set_sighandler (SIGINT, rl_signal_handler, &old_int);
283      rl_maybe_set_sighandler (SIGTERM, rl_signal_handler, &old_term);
284      rl_maybe_set_sighandler (SIGQUIT, rl_signal_handler, &old_quit);
285
286      oh = rl_set_sighandler (SIGALRM, rl_signal_handler, &old_alrm);
287      if (oh == (SigHandler *)SIG_IGN)
288	rl_sigaction (SIGALRM, &old_alrm, &dummy);
289#if defined (HAVE_POSIX_SIGNALS) && defined (SA_RESTART)
290      /* If the application using readline has already installed a signal
291	 handler with SA_RESTART, SIGALRM will cause reads to be restarted
292	 automatically, so readline should just get out of the way.  Since
293	 we tested for SIG_IGN above, we can just test for SIG_DFL here. */
294      if (oh != (SigHandler *)SIG_DFL && (old_alrm.sa_flags & SA_RESTART))
295	rl_sigaction (SIGALRM, &old_alrm, &dummy);
296#endif /* HAVE_POSIX_SIGNALS */
297
298#if defined (SIGTSTP)
299      rl_maybe_set_sighandler (SIGTSTP, rl_signal_handler, &old_tstp);
300#endif /* SIGTSTP */
301
302#if defined (SIGTTOU)
303      rl_maybe_set_sighandler (SIGTTOU, rl_signal_handler, &old_ttou);
304#endif /* SIGTTOU */
305
306#if defined (SIGTTIN)
307      rl_maybe_set_sighandler (SIGTTIN, rl_signal_handler, &old_ttin);
308#endif /* SIGTTIN */
309
310      signals_set_flag = 1;
311    }
312
313#if defined (SIGWINCH)
314  if (rl_catch_sigwinch && sigwinch_set_flag == 0)
315    {
316      rl_maybe_set_sighandler (SIGWINCH, rl_sigwinch_handler, &old_winch);
317      sigwinch_set_flag = 1;
318    }
319#endif /* SIGWINCH */
320
321  return 0;
322}
323
324int
325rl_clear_signals ()
326{
327  sighandler_cxt dummy;
328
329  if (rl_catch_signals && signals_set_flag == 1)
330    {
331      sigemptyset (&dummy.sa_mask);
332
333      rl_sigaction (SIGINT, &old_int, &dummy);
334      rl_sigaction (SIGTERM, &old_term, &dummy);
335      rl_sigaction (SIGQUIT, &old_quit, &dummy);
336      rl_sigaction (SIGALRM, &old_alrm, &dummy);
337
338#if defined (SIGTSTP)
339      rl_sigaction (SIGTSTP, &old_tstp, &dummy);
340#endif /* SIGTSTP */
341
342#if defined (SIGTTOU)
343      rl_sigaction (SIGTTOU, &old_ttou, &dummy);
344#endif /* SIGTTOU */
345
346#if defined (SIGTTIN)
347      rl_sigaction (SIGTTIN, &old_ttin, &dummy);
348#endif /* SIGTTIN */
349
350      signals_set_flag = 0;
351    }
352
353#if defined (SIGWINCH)
354  if (rl_catch_sigwinch && sigwinch_set_flag == 1)
355    {
356      sigemptyset (&dummy.sa_mask);
357      rl_sigaction (SIGWINCH, &old_winch, &dummy);
358      sigwinch_set_flag = 0;
359    }
360#endif
361
362  return 0;
363}
364
365/* Clean up the terminal and readline state after catching a signal, before
366   resending it to the calling application. */
367void
368rl_cleanup_after_signal ()
369{
370  _rl_clean_up_for_exit ();
371  (*rl_deprep_term_function) ();
372  rl_clear_signals ();
373  rl_clear_pending_input ();
374}
375
376/* Reset the terminal and readline state after a signal handler returns. */
377void
378rl_reset_after_signal ()
379{
380  (*rl_prep_term_function) (_rl_meta_flag);
381  rl_set_signals ();
382}
383
384/* Free up the readline variable line state for the current line (undo list,
385   any partial history entry, any keyboard macros in progress, and any
386   numeric arguments in process) after catching a signal, before calling
387   rl_cleanup_after_signal(). */
388void
389rl_free_line_state ()
390{
391  register HIST_ENTRY *entry;
392
393  rl_free_undo_list ();
394
395  entry = current_history ();
396  if (entry)
397    entry->data = (char *)NULL;
398
399  _rl_kill_kbd_macro ();
400  rl_clear_message ();
401  _rl_init_argument ();
402}
403
404#endif  /* HANDLE_SIGNALS */
405