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