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