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