]> git.ipfire.org Git - thirdparty/bash.git/blob - sig.c
Imported from ../bash-2.01.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, 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
50 extern int last_command_exit_value;
51 extern int return_catch_flag;
52 extern int loop_level, continuing, breaking;
53 extern int parse_and_execute_level, shell_initialized;
54 extern int interactive, interactive_shell, login_shell, startup_state;
55
56 /* Non-zero after SIGINT. */
57 int interrupt_state;
58
59 /* The environment at the top-level R-E loop. We use this in
60 the case of error return. */
61 procenv_t top_level;
62
63 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
64 /* The signal masks that this shell runs with. */
65 sigset_t top_level_mask;
66 #endif /* JOB_CONTROL */
67
68 /* When non-zero, we throw_to_top_level (). */
69 int interrupt_immediately = 0;
70
71 static void initialize_shell_signals ();
72
73 void
74 initialize_signals ()
75 {
76 initialize_shell_signals ();
77 initialize_job_signals ();
78 #if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
79 initialize_siglist ();
80 #endif
81 }
82
83 void
84 reinitialize_signals ()
85 {
86 initialize_shell_signals (1);
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. */
93 struct 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. */
103 static 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 static int termsigs_initialized = 0;
195
196 /* Initialize signals that will terminate the shell to do some
197 unwind protection. For non-interactive shells, we only call
198 this when a trap is defined for EXIT (0). */
199 void
200 initialize_terminating_signals ()
201 {
202 register int i;
203 #if defined (HAVE_POSIX_SIGNALS)
204 struct sigaction act, oact;
205 #endif
206
207 if (termsigs_initialized)
208 return;
209
210 /* The following code is to avoid an expensive call to
211 set_signal_handler () for each terminating_signals. Fortunately,
212 this is possible in Posix. Unfortunately, we have to call signal ()
213 on non-Posix systems for each signal in terminating_signals. */
214 #if defined (HAVE_POSIX_SIGNALS)
215 act.sa_handler = termination_unwind_protect;
216 act.sa_flags = 0;
217 sigemptyset (&act.sa_mask);
218 sigemptyset (&oact.sa_mask);
219 for (i = 0; i < TERMSIGS_LENGTH; i++)
220 sigaddset (&act.sa_mask, XSIG (i));
221 for (i = 0; i < TERMSIGS_LENGTH; i++)
222 {
223 sigaction (XSIG (i), &act, &oact);
224 XHANDLER(i) = oact.sa_handler;
225 /* Don't do anything with signals that are ignored at shell entry
226 if the shell is not interactive. */
227 if (!interactive_shell && XHANDLER (i) == SIG_IGN)
228 {
229 sigaction (XSIG (i), &oact, &act);
230 set_signal_ignored (XSIG (i));
231 }
232 if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
233 sigaction (XSIG (i), &oact, (struct sigaction *)NULL);
234 }
235
236 #else /* !HAVE_POSIX_SIGNALS */
237
238 for (i = 0; i < TERMSIGS_LENGTH; i++)
239 {
240 XHANDLER(i) = signal (XSIG (i), termination_unwind_protect);
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 signal (XSIG (i), SIG_IGN);
246 set_signal_ignored (XSIG (i));
247 }
248 if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
249 signal (XSIG (i), XHANDLER (i));
250 }
251
252 #endif /* !HAVE_POSIX_SIGNALS */
253
254 termsigs_initialized = 1;
255 }
256
257 static void
258 initialize_shell_signals ()
259 {
260 if (interactive)
261 initialize_terminating_signals ();
262
263 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
264 /* All shells use the signal mask they inherit, and pass it along
265 to child processes. Children will never block SIGCHLD, though. */
266 sigemptyset (&top_level_mask);
267 sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask);
268 sigdelset (&top_level_mask, SIGCHLD);
269 #endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
270
271 /* And, some signals that are specifically ignored by the shell. */
272 set_signal_handler (SIGQUIT, SIG_IGN);
273
274 if (interactive)
275 {
276 set_signal_handler (SIGINT, sigint_sighandler);
277 set_signal_handler (SIGTERM, SIG_IGN);
278 }
279 }
280
281 void
282 reset_terminating_signals ()
283 {
284 register int i;
285 #if defined (HAVE_POSIX_SIGNALS)
286 struct sigaction act;
287 #endif
288
289 if (termsigs_initialized == 0)
290 return;
291
292 #if defined (HAVE_POSIX_SIGNALS)
293 act.sa_flags = 0;
294 sigemptyset (&act.sa_mask);
295 for (i = 0; i < TERMSIGS_LENGTH; i++)
296 {
297 /* Skip a signal if it's trapped or handled specially, because the
298 trap code will restore the correct value. */
299 if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
300 continue;
301
302 act.sa_handler = XHANDLER (i);
303 sigaction (XSIG (i), &act, (struct sigaction *) NULL);
304 }
305 #else /* !HAVE_POSIX_SIGNALS */
306 for (i = 0; i < TERMSIGS_LENGTH; i++)
307 {
308 if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
309 continue;
310
311 signal (XSIG (i), XHANDLER (i));
312 }
313 #endif /* !HAVE_POSIX_SIGNALS */
314 }
315 #undef XSIG
316 #undef XHANDLER
317
318 /* What to do when we've been interrupted, and it is safe to handle it. */
319 void
320 throw_to_top_level ()
321 {
322 int print_newline = 0;
323
324 if (interrupt_state)
325 {
326 print_newline = 1;
327 DELINTERRUPT;
328 }
329
330 if (interrupt_state)
331 return;
332
333 last_command_exit_value |= 128;
334
335 /* Run any traps set on SIGINT. */
336 run_interrupt_trap ();
337
338 /* Cleanup string parser environment. */
339 while (parse_and_execute_level)
340 parse_and_execute_cleanup ();
341
342 #if defined (JOB_CONTROL)
343 give_terminal_to (shell_pgrp);
344 #endif /* JOB_CONTROL */
345
346 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
347 /* This should not be necessary on systems using sigsetjmp/siglongjmp. */
348 sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
349 #endif
350
351 reset_parser ();
352
353 #if defined (READLINE)
354 if (interactive)
355 bashline_reinitialize ();
356 #endif /* READLINE */
357
358 #if defined (PROCESS_SUBSTITUTION)
359 unlink_fifo_list ();
360 #endif /* PROCESS_SUBSTITUTION */
361
362 run_unwind_protects ();
363 loop_level = continuing = breaking = 0;
364 return_catch_flag = 0;
365
366 if (interactive && print_newline)
367 {
368 fflush (stdout);
369 fprintf (stderr, "\n");
370 fflush (stderr);
371 }
372
373 /* An interrupted `wait' command in a script does not exit the script. */
374 if (interactive || (interactive_shell && !shell_initialized) ||
375 (print_newline && signal_is_trapped (SIGINT)))
376 jump_to_top_level (DISCARD);
377 else
378 jump_to_top_level (EXITPROG);
379 }
380
381 /* This is just here to isolate the longjmp calls. */
382 void
383 jump_to_top_level (value)
384 int value;
385 {
386 longjmp (top_level, value);
387 }
388
389 sighandler
390 termination_unwind_protect (sig)
391 int sig;
392 {
393 if (sig == SIGINT && signal_is_trapped (SIGINT))
394 run_interrupt_trap ();
395
396 #if defined (HISTORY)
397 if (interactive_shell && sig != SIGABRT)
398 maybe_save_shell_history ();
399 #endif /* HISTORY */
400
401 #if defined (JOB_CONTROL)
402 if (interactive && sig == SIGHUP)
403 hangup_all_jobs ();
404 end_job_control ();
405 #endif /* JOB_CONTROL */
406
407 #if defined (PROCESS_SUBSTITUTION)
408 unlink_fifo_list ();
409 #endif /* PROCESS_SUBSTITUTION */
410
411 run_exit_trap ();
412 set_signal_handler (sig, SIG_DFL);
413 kill (getpid (), sig);
414
415 SIGRETURN (0);
416 }
417
418 /* What we really do when SIGINT occurs. */
419 sighandler
420 sigint_sighandler (sig)
421 int sig;
422 {
423 #if defined (MUST_REINSTALL_SIGHANDLERS)
424 signal (sig, sigint_sighandler);
425 #endif
426
427 /* interrupt_state needs to be set for the stack of interrupts to work
428 right. Should it be set unconditionally? */
429 if (interrupt_state == 0)
430 ADDINTERRUPT;
431
432 if (interrupt_immediately)
433 {
434 interrupt_immediately = 0;
435 throw_to_top_level ();
436 }
437
438 SIGRETURN (0);
439 }
440
441 /* Signal functions used by the rest of the code. */
442 #if !defined (HAVE_POSIX_SIGNALS)
443
444 #if defined (JOB_CONTROL)
445 /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
446 sigprocmask (operation, newset, oldset)
447 int operation, *newset, *oldset;
448 {
449 int old, new;
450
451 if (newset)
452 new = *newset;
453 else
454 new = 0;
455
456 switch (operation)
457 {
458 case SIG_BLOCK:
459 old = sigblock (new);
460 break;
461
462 case SIG_SETMASK:
463 sigsetmask (new);
464 break;
465
466 default:
467 internal_error ("Bad code in sig.c: sigprocmask");
468 }
469
470 if (oldset)
471 *oldset = old;
472 }
473 #endif /* JOB_CONTROL */
474
475 #else
476
477 #if !defined (SA_INTERRUPT)
478 # define SA_INTERRUPT 0
479 #endif
480
481 #if !defined (SA_RESTART)
482 # define SA_RESTART 0
483 #endif
484
485 SigHandler *
486 set_signal_handler (sig, handler)
487 int sig;
488 SigHandler *handler;
489 {
490 struct sigaction act, oact;
491
492 act.sa_handler = handler;
493 act.sa_flags = 0;
494 #if 0
495 if (sig == SIGALRM)
496 act.sa_flags |= SA_INTERRUPT; /* XXX */
497 else
498 act.sa_flags |= SA_RESTART; /* XXX */
499 #endif
500 sigemptyset (&act.sa_mask);
501 sigemptyset (&oact.sa_mask);
502 sigaction (sig, &act, &oact);
503 return (oact.sa_handler);
504 }
505 #endif /* HAVE_POSIX_SIGNALS */