]> git.ipfire.org Git - thirdparty/bash.git/blob - sig.c
Imported from ../bash-2.05a.tar.gz.
[thirdparty/bash.git] / sig.c
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, 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 "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
53 extern int last_command_exit_value;
54 extern int return_catch_flag;
55 extern int loop_level, continuing, breaking;
56 extern int parse_and_execute_level, shell_initialized;
57 extern int startup_state;
58
59 /* Non-zero after SIGINT. */
60 int interrupt_state;
61
62 /* The environment at the top-level R-E loop. We use this in
63 the case of error return. */
64 procenv_t top_level;
65
66 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
67 /* The signal masks that this shell runs with. */
68 sigset_t top_level_mask;
69 #endif /* JOB_CONTROL */
70
71 /* When non-zero, we throw_to_top_level (). */
72 int interrupt_immediately = 0;
73
74 static void initialize_shell_signals __P((void));
75
76 void
77 initialize_signals ()
78 {
79 initialize_shell_signals ();
80 initialize_job_signals ();
81 #if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
82 initialize_siglist ();
83 #endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */
84 }
85
86 void
87 reinitialize_signals ()
88 {
89 initialize_shell_signals ();
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. */
96 struct 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. */
106 static 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
175 #if 0
176 #ifdef SIGPROF
177 { SIGPROF, NULL_HANDLER },
178 #endif
179 #endif
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
199 static int termsigs_initialized = 0;
200
201 /* Initialize signals that will terminate the shell to do some
202 unwind protection. For non-interactive shells, we only call
203 this when a trap is defined for EXIT (0). */
204 void
205 initialize_terminating_signals ()
206 {
207 register int i;
208 #if defined (HAVE_POSIX_SIGNALS)
209 struct sigaction act, oact;
210 #endif
211
212 if (termsigs_initialized)
213 return;
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)
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);
229 XHANDLER(i) = oact.sa_handler;
230 /* Don't do anything with signals that are ignored at shell entry
231 if the shell is not interactive. */
232 if (!interactive_shell && XHANDLER (i) == SIG_IGN)
233 {
234 sigaction (XSIG (i), &oact, &act);
235 set_signal_ignored (XSIG (i));
236 }
237 #if defined (SIGPROF) && !defined (_MINIX)
238 if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
239 sigaction (XSIG (i), &oact, (struct sigaction *)NULL);
240 #endif /* SIGPROF && !_MINIX */
241 }
242
243 #else /* !HAVE_POSIX_SIGNALS */
244
245 for (i = 0; i < TERMSIGS_LENGTH; i++)
246 {
247 XHANDLER(i) = signal (XSIG (i), termination_unwind_protect);
248 /* Don't do anything with signals that are ignored at shell entry
249 if the shell is not interactive. */
250 if (!interactive_shell && XHANDLER (i) == SIG_IGN)
251 {
252 signal (XSIG (i), SIG_IGN);
253 set_signal_ignored (XSIG (i));
254 }
255 #ifdef SIGPROF
256 if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
257 signal (XSIG (i), XHANDLER (i));
258 #endif
259 }
260
261 #endif /* !HAVE_POSIX_SIGNALS */
262
263 termsigs_initialized = 1;
264 }
265
266 static void
267 initialize_shell_signals ()
268 {
269 if (interactive)
270 initialize_terminating_signals ();
271
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);
277 # if defined (SIGCHLD)
278 sigdelset (&top_level_mask, SIGCHLD);
279 # endif
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
292 void
293 reset_terminating_signals ()
294 {
295 register int i;
296 #if defined (HAVE_POSIX_SIGNALS)
297 struct sigaction act;
298 #endif
299
300 if (termsigs_initialized == 0)
301 return;
302
303 #if defined (HAVE_POSIX_SIGNALS)
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. */
330 void
331 throw_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)
354 give_terminal_to (shell_pgrp, 0);
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. */
393 void
394 jump_to_top_level (value)
395 int value;
396 {
397 longjmp (top_level, value);
398 }
399
400 sighandler
401 termination_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. */
430 sighandler
431 sigint_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. */
457 sigprocmask (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
496 SigHandler *
497 set_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 */