source: vendor/bash/3.1/sig.c@ 3590

Last change on this file since 3590 was 3228, checked in by bird, 18 years ago

bash 3.1

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