1/* signal.c
2   Signal handling routines.
3
4   Copyright (C) 1992 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucp.h"
26
27#include "uudefs.h"
28#include "sysdep.h"
29#include "system.h"
30
31#include <errno.h>
32
33/* Signal handling routines.  When we catch a signal, we want to set
34   the appropriate elements of afSignal and afLog_signal to TRUE.  If
35   we are on a system which restarts system calls, we may also want to
36   longjmp out.  On a system which does not restart system calls,
37   these signal handling routines are well-defined by ANSI C.  */
38
39#if HAVE_RESTARTABLE_SYSCALLS
40volatile sig_atomic_t fSjmp;
41volatile jmp_buf sSjmp_buf;
42#endif /* HAVE_RESTARTABLE_SYSCALLS */
43
44/* Some systems, such as SunOS, have a SA_INTERRUPT bit that must be
45   set in the sigaction structure to force system calls to be
46   interrupted.  */
47#ifndef SA_INTERRUPT
48#define SA_INTERRUPT 0
49#endif
50
51/* The SVR3 sigset function can be called just like signal, unless
52   system calls are restarted which is extremely unlikely; we prevent
53   this case in sysh.unx.  */
54#if HAVE_SIGSET && ! HAVE_SIGACTION && ! HAVE_SIGVEC
55#define signal sigset
56#endif
57
58/* The sigvec structure changed from 4.2BSD to 4.3BSD.  These macros
59   make the 4.3 code backward compatible.  */
60#ifndef SV_INTERRUPT
61#define SV_INTERRUPT 0
62#endif
63#if ! HAVE_SIGVEC_SV_FLAGS
64#define sv_flags sv_onstack
65#endif
66
67/* Catch a signal.  Reinstall the signal handler if necessary, set the
68   appropriate variables, and do a longjmp if necessary.  */
69
70RETSIGTYPE
71ussignal (isig)
72     int isig;
73{
74  int iindex;
75
76#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
77  (void) signal (isig, ussignal);
78#endif
79
80  switch (isig)
81    {
82    default: iindex = INDEXSIG_SIGHUP; break;
83#ifdef SIGINT
84    case SIGINT: iindex = INDEXSIG_SIGINT; break;
85#endif
86#ifdef SIGQUIT
87    case SIGQUIT: iindex = INDEXSIG_SIGQUIT; break;
88#endif
89#ifdef SIGTERM
90    case SIGTERM: iindex = INDEXSIG_SIGTERM; break;
91#endif
92#ifdef SIGPIPE
93    case SIGPIPE: iindex = INDEXSIG_SIGPIPE; break;
94#endif
95    }
96
97  afSignal[iindex] = TRUE;
98  afLog_signal[iindex] = TRUE;
99
100#if HAVE_RESTARTABLE_SYSCALLS
101  if (fSjmp)
102    longjmp (sSjmp_buf, 1);
103#endif /* HAVE_RESTARTABLE_SYSCALLS */
104}
105
106/* Prepare to catch a signal.  This is basically the ANSI C routine
107   signal, but it uses sigaction or sigvec instead if they are
108   available.  If fforce is FALSE, we do not set the signal if it is
109   currently being ignored.  If pfignored is not NULL and fforce is
110   FALSE, then *pfignored will be set to TRUE if the signal was
111   previously being ignored (if fforce is TRUE the value returned in
112   *pfignored is meaningless).  If we can't change the signal handler
113   we give a fatal error.  */
114
115void
116usset_signal (isig, pfn, fforce, pfignored)
117     int isig;
118     RETSIGTYPE (*pfn) P((int));
119     boolean fforce;
120     boolean *pfignored;
121{
122#if HAVE_SIGACTION
123
124  struct sigaction s;
125
126  if (! fforce)
127    {
128      (void) (sigemptyset (&s.sa_mask));
129      if (sigaction (isig, (struct sigaction *) NULL, &s) != 0)
130	ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno));
131
132      if (s.sa_handler == SIG_IGN)
133	{
134	  if (pfignored != NULL)
135	    *pfignored = TRUE;
136	  return;
137	}
138
139      if (pfignored != NULL)
140	*pfignored = FALSE;
141    }
142
143  s.sa_handler = pfn;
144  (void) (sigemptyset (&s.sa_mask));
145  s.sa_flags = SA_INTERRUPT;
146
147  if (sigaction (isig, &s, (struct sigaction *) NULL) != 0)
148    ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno));
149
150#else /* ! HAVE_SIGACTION */
151#if HAVE_SIGVEC
152
153  struct sigvec s;
154
155  if (! fforce)
156    {
157      if (sigvec (isig, (struct sigvec *) NULL, &s) != 0)
158	ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno));
159
160      if (s.sv_handler == SIG_IGN)
161	{
162	  if (pfignored != NULL)
163	    *pfignored = TRUE;
164	  return;
165	}
166
167      if (pfignored != NULL)
168	*pfignored = FALSE;
169    }
170
171  s.sv_handler = pfn;
172  s.sv_mask = 0;
173  s.sv_flags = SV_INTERRUPT;
174
175  if (sigvec (isig, &s, (struct sigvec *) NULL) != 0)
176    ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno));
177
178#else /* ! HAVE_SIGVEC */
179
180  if (! fforce)
181    {
182      if (signal (isig, SIG_IGN) == SIG_IGN)
183	{
184	  if (pfignored != NULL)
185	    *pfignored = TRUE;
186	  return;
187	}
188
189      if (pfignored != NULL)
190	*pfignored = FALSE;
191    }
192
193  (void) signal (isig, pfn);
194
195#endif /* ! HAVE_SIGVEC */
196#endif /* ! HAVE_SIGACTION */
197}
198
199/* The routine called by the system independent code, which always
200   uses the same signal handler.  */
201
202void
203usysdep_signal (isig)
204     int isig;
205{
206  usset_signal (isig, ussignal, FALSE, (boolean *) NULL);
207}
208