]> git.ipfire.org Git - thirdparty/bash.git/blame - sig.c
Imported from ../bash-2.0.tar.gz.
[thirdparty/bash.git] / sig.c
CommitLineData
ccc6cda3
JA
1/* sig.c - interface for shell signal handlers and signal initialization. */
2
3/* Copyright (C) 1994 Free Software Foundation, Inc.
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21#include "config.h"
22
23#include "bashtypes.h"
24
25#if defined (HAVE_UNISTD_H)
26# include <unistd.h>
27#endif
28
29#include <stdio.h>
30#include <signal.h>
31
32#include "shell.h"
33#if defined (JOB_CONTROL)
34#include "jobs.h"
35#endif /* JOB_CONTROL */
36#include "siglist.h"
37#include "sig.h"
38#include "trap.h"
39
40#include "builtins/common.h"
41
42#if defined (READLINE)
43# include "bashline.h"
44#endif
45
46#if defined (HISTORY)
47# include "bashhist.h"
48#endif
49
50extern int last_command_exit_value;
51extern int return_catch_flag;
52extern int loop_level, continuing, breaking;
53extern int parse_and_execute_level, shell_initialized;
54extern int interactive, interactive_shell, login_shell, startup_state;
55
56/* Non-zero after SIGINT. */
57int interrupt_state;
58
59/* The environment at the top-level R-E loop. We use this in
60 the case of error return. */
61procenv_t top_level;
62
63#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
64/* The signal masks that this shell runs with. */
65sigset_t top_level_mask;
66#endif /* JOB_CONTROL */
67
68/* When non-zero, we throw_to_top_level (). */
69int interrupt_immediately = 0;
70
71static void initialize_terminating_signals ();
72
73void
74initialize_signals ()
75{
76 initialize_terminating_signals ();
77 initialize_job_signals ();
78#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
79 initialize_siglist ();
80#endif
81}
82
83void
84reinitialize_signals ()
85{
86 initialize_terminating_signals ();
87 initialize_job_signals ();
88}
89
90/* A structure describing a signal that terminates the shell if not
91 caught. The orig_handler member is present so children can reset
92 these signals back to their original handlers. */
93struct termsig {
94 int signum;
95 SigHandler *orig_handler;
96};
97
98#define NULL_HANDLER (SigHandler *)SIG_DFL
99
100/* The list of signals that would terminate the shell if not caught.
101 We catch them, but just so that we can write the history file,
102 and so forth. */
103static struct termsig terminating_signals[] = {
104#ifdef SIGHUP
105 SIGHUP, NULL_HANDLER,
106#endif
107
108#ifdef SIGINT
109 SIGINT, NULL_HANDLER,
110#endif
111
112#ifdef SIGILL
113 SIGILL, NULL_HANDLER,
114#endif
115
116#ifdef SIGTRAP
117 SIGTRAP, NULL_HANDLER,
118#endif
119
120#ifdef SIGIOT
121 SIGIOT, NULL_HANDLER,
122#endif
123
124#ifdef SIGDANGER
125 SIGDANGER, NULL_HANDLER,
126#endif
127
128#ifdef SIGEMT
129 SIGEMT, NULL_HANDLER,
130#endif
131
132#ifdef SIGFPE
133 SIGFPE, NULL_HANDLER,
134#endif
135
136#ifdef SIGBUS
137 SIGBUS, NULL_HANDLER,
138#endif
139
140#ifdef SIGSEGV
141 SIGSEGV, NULL_HANDLER,
142#endif
143
144#ifdef SIGSYS
145 SIGSYS, NULL_HANDLER,
146#endif
147
148#ifdef SIGPIPE
149 SIGPIPE, NULL_HANDLER,
150#endif
151
152#ifdef SIGALRM
153 SIGALRM, NULL_HANDLER,
154#endif
155
156#ifdef SIGTERM
157 SIGTERM, NULL_HANDLER,
158#endif
159
160#ifdef SIGXCPU
161 SIGXCPU, NULL_HANDLER,
162#endif
163
164#ifdef SIGXFSZ
165 SIGXFSZ, NULL_HANDLER,
166#endif
167
168#ifdef SIGVTALRM
169 SIGVTALRM, NULL_HANDLER,
170#endif
171
172#ifdef SIGPROF
173 SIGPROF, NULL_HANDLER,
174#endif
175
176#ifdef SIGLOST
177 SIGLOST, NULL_HANDLER,
178#endif
179
180#ifdef SIGUSR1
181 SIGUSR1, NULL_HANDLER,
182#endif
183
184#ifdef SIGUSR2
185 SIGUSR2, NULL_HANDLER,
186#endif
187};
188
189#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig))
190
191#define XSIG(x) (terminating_signals[x].signum)
192#define XHANDLER(x) (terminating_signals[x].orig_handler)
193
194/* Initialize signals that will terminate the shell to do some
195 unwind protection. */
196static void
197initialize_terminating_signals ()
198{
199 register int i;
200
201 /* The following code is to avoid an expensive call to
202 set_signal_handler () for each terminating_signals. Fortunately,
203 this is possible in Posix. Unfortunately, we have to call signal ()
204 on non-Posix systems for each signal in terminating_signals. */
205#if defined (HAVE_POSIX_SIGNALS)
206 struct sigaction act, oact;
207
208 act.sa_handler = termination_unwind_protect;
209 act.sa_flags = 0;
210 sigemptyset (&act.sa_mask);
211 sigemptyset (&oact.sa_mask);
212 for (i = 0; i < TERMSIGS_LENGTH; i++)
213 sigaddset (&act.sa_mask, XSIG (i));
214 for (i = 0; i < TERMSIGS_LENGTH; i++)
215 {
216 sigaction (XSIG (i), &act, &oact);
217 terminating_signals[i].orig_handler = oact.sa_handler;
218 /* Don't do anything with signals that are ignored at shell entry
219 if the shell is not interactive. */
220 if (!interactive_shell && oact.sa_handler == SIG_IGN)
221 {
222 sigaction (XSIG (i), &oact, &act);
223 set_signal_ignored (XSIG (i));
224 }
225 }
226
227#else /* !HAVE_POSIX_SIGNALS */
228
229 for (i = 0; i < TERMSIGS_LENGTH; i++)
230 {
231 terminating_signals[i].orig_handler =
232 signal (XSIG (i), termination_unwind_protect);
233 /* Don't do anything with signals that are ignored at shell entry
234 if the shell is not interactive. */
235 if (!interactive_shell && terminating_signals[i].orig_handler == SIG_IGN)
236 {
237 signal (XSIG (i), SIG_IGN);
238 set_signal_ignored (XSIG (i));
239 }
240 }
241
242#endif /* !HAVE_POSIX_SIGNALS */
243
244#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
245 /* All shells use the signal mask they inherit, and pass it along
246 to child processes. Children will never block SIGCHLD, though. */
247 sigemptyset (&top_level_mask);
248 sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask);
249 sigdelset (&top_level_mask, SIGCHLD);
250#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
251
252 /* And, some signals that are specifically ignored by the shell. */
253 set_signal_handler (SIGQUIT, SIG_IGN);
254
255 if (interactive)
256 {
257 set_signal_handler (SIGINT, sigint_sighandler);
258 set_signal_handler (SIGTERM, SIG_IGN);
259 }
260}
261
262void
263reset_terminating_signals ()
264{
265 register int i;
266
267#if defined (HAVE_POSIX_SIGNALS)
268 struct sigaction act;
269
270 act.sa_flags = 0;
271 sigemptyset (&act.sa_mask);
272 for (i = 0; i < TERMSIGS_LENGTH; i++)
273 {
274 /* Skip a signal if it's trapped or handled specially, because the
275 trap code will restore the correct value. */
276 if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
277 continue;
278
279 act.sa_handler = XHANDLER (i);
280 sigaction (XSIG (i), &act, (struct sigaction *) NULL);
281 }
282#else /* !HAVE_POSIX_SIGNALS */
283 for (i = 0; i < TERMSIGS_LENGTH; i++)
284 {
285 if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
286 continue;
287
288 signal (XSIG (i), XHANDLER (i));
289 }
290#endif /* !HAVE_POSIX_SIGNALS */
291}
292#undef XSIG
293#undef XHANDLER
294
295/* What to do when we've been interrupted, and it is safe to handle it. */
296void
297throw_to_top_level ()
298{
299 int print_newline = 0;
300
301 if (interrupt_state)
302 {
303 print_newline = 1;
304 DELINTERRUPT;
305 }
306
307 if (interrupt_state)
308 return;
309
310 last_command_exit_value |= 128;
311
312 /* Run any traps set on SIGINT. */
313 run_interrupt_trap ();
314
315 /* Cleanup string parser environment. */
316 while (parse_and_execute_level)
317 parse_and_execute_cleanup ();
318
319#if defined (JOB_CONTROL)
320 give_terminal_to (shell_pgrp);
321#endif /* JOB_CONTROL */
322
323#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
324 /* This should not be necessary on systems using sigsetjmp/siglongjmp. */
325 sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
326#endif
327
328 reset_parser ();
329
330#if defined (READLINE)
331 if (interactive)
332 bashline_reinitialize ();
333#endif /* READLINE */
334
335#if defined (PROCESS_SUBSTITUTION)
336 unlink_fifo_list ();
337#endif /* PROCESS_SUBSTITUTION */
338
339 run_unwind_protects ();
340 loop_level = continuing = breaking = 0;
341 return_catch_flag = 0;
342
343 if (interactive && print_newline)
344 {
345 fflush (stdout);
346 fprintf (stderr, "\n");
347 fflush (stderr);
348 }
349
350 /* An interrupted `wait' command in a script does not exit the script. */
351 if (interactive || (interactive_shell && !shell_initialized) ||
352 (print_newline && signal_is_trapped (SIGINT)))
353 jump_to_top_level (DISCARD);
354 else
355 jump_to_top_level (EXITPROG);
356}
357
358/* This is just here to isolate the longjmp calls. */
359void
360jump_to_top_level (value)
361 int value;
362{
363 longjmp (top_level, value);
364}
365
366sighandler
367termination_unwind_protect (sig)
368 int sig;
369{
370 if (sig == SIGINT && signal_is_trapped (SIGINT))
371 run_interrupt_trap ();
372
373#if defined (HISTORY)
374 if (interactive_shell && sig != SIGABRT)
375 maybe_save_shell_history ();
376#endif /* HISTORY */
377
378#if defined (JOB_CONTROL)
379 if (interactive && sig == SIGHUP)
380 hangup_all_jobs ();
381 end_job_control ();
382#endif /* JOB_CONTROL */
383
384#if defined (PROCESS_SUBSTITUTION)
385 unlink_fifo_list ();
386#endif /* PROCESS_SUBSTITUTION */
387
388 run_exit_trap ();
389 set_signal_handler (sig, SIG_DFL);
390 kill (getpid (), sig);
391
392 SIGRETURN (0);
393}
394
395/* What we really do when SIGINT occurs. */
396sighandler
397sigint_sighandler (sig)
398 int sig;
399{
400#if defined (MUST_REINSTALL_SIGHANDLERS)
401 signal (sig, sigint_sighandler);
402#endif
403
404 /* interrupt_state needs to be set for the stack of interrupts to work
405 right. Should it be set unconditionally? */
406 if (interrupt_state == 0)
407 ADDINTERRUPT;
408
409 if (interrupt_immediately)
410 {
411 interrupt_immediately = 0;
412 throw_to_top_level ();
413 }
414
415 SIGRETURN (0);
416}
417
418/* Signal functions used by the rest of the code. */
419#if !defined (HAVE_POSIX_SIGNALS)
420
421#if defined (JOB_CONTROL)
422/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
423sigprocmask (operation, newset, oldset)
424 int operation, *newset, *oldset;
425{
426 int old, new;
427
428 if (newset)
429 new = *newset;
430 else
431 new = 0;
432
433 switch (operation)
434 {
435 case SIG_BLOCK:
436 old = sigblock (new);
437 break;
438
439 case SIG_SETMASK:
440 sigsetmask (new);
441 break;
442
443 default:
444 internal_error ("Bad code in sig.c: sigprocmask");
445 }
446
447 if (oldset)
448 *oldset = old;
449}
450#endif /* JOB_CONTROL */
451
452#else
453
454#if !defined (SA_INTERRUPT)
455# define SA_INTERRUPT 0
456#endif
457
458#if !defined (SA_RESTART)
459# define SA_RESTART 0
460#endif
461
462SigHandler *
463set_signal_handler (sig, handler)
464 int sig;
465 SigHandler *handler;
466{
467 struct sigaction act, oact;
468
469 act.sa_handler = handler;
470 act.sa_flags = 0;
471#if 0
472 if (sig == SIGALRM)
473 act.sa_flags |= SA_INTERRUPT; /* XXX */
474 else
475 act.sa_flags |= SA_RESTART; /* XXX */
476#endif
477 sigemptyset (&act.sa_mask);
478 sigemptyset (&oact.sa_mask);
479 sigaction (sig, &act, &oact);
480 return (oact.sa_handler);
481}
482#endif /* HAVE_POSIX_SIGNALS */