]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
1 | This file is trap.def, from which is created trap.c. |
2 | It implements the builtin "trap" in Bash. | |
3 | ||
495aee44 | 4 | Copyright (C) 1987-2010 Free Software Foundation, Inc. |
726f6388 JA |
5 | |
6 | This file is part of GNU Bash, the Bourne Again SHell. | |
7 | ||
3185942a JA |
8 | Bash is free software: you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation, either version 3 of the License, or | |
11 | (at your option) any later version. | |
726f6388 | 12 | |
3185942a JA |
13 | Bash is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
726f6388 | 17 | |
3185942a JA |
18 | You should have received a copy of the GNU General Public License |
19 | along with Bash. If not, see <http://www.gnu.org/licenses/>. | |
726f6388 JA |
20 | |
21 | $PRODUCES trap.c | |
22 | ||
23 | $BUILTIN trap | |
24 | $FUNCTION trap_builtin | |
3185942a JA |
25 | $SHORT_DOC trap [-lp] [[arg] signal_spec ...] |
26 | Trap signals and other events. | |
27 | ||
28 | Defines and activates handlers to be run when the shell receives signals | |
29 | or other conditions. | |
30 | ||
31 | ARG is a command to be read and executed when the shell receives the | |
b80f6443 JA |
32 | signal(s) SIGNAL_SPEC. If ARG is absent (and a single SIGNAL_SPEC |
33 | is supplied) or `-', each specified signal is reset to its original | |
34 | value. If ARG is the null string each SIGNAL_SPEC is ignored by the | |
3185942a JA |
35 | shell and by the commands it invokes. |
36 | ||
37 | If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell. If | |
495aee44 CR |
38 | a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command. If |
39 | a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a | |
40 | script run by the . or source builtins finishes executing. A SIGNAL_SPEC | |
41 | of ERR means to execute ARG each time a command's failure would cause the | |
42 | shell to exit when the -e option is enabled. | |
3185942a JA |
43 | |
44 | If no arguments are supplied, trap prints the list of commands associated | |
45 | with each signal. | |
46 | ||
47 | Options: | |
48 | -l print a list of signal names and their corresponding numbers | |
49 | -p display the trap commands associated with each SIGNAL_SPEC | |
50 | ||
51 | Each SIGNAL_SPEC is either a signal name in <signal.h> or a signal number. | |
52 | Signal names are case insensitive and the SIG prefix is optional. A | |
53 | signal may be sent to the shell with "kill -signal $$". | |
54 | ||
55 | Exit Status: | |
56 | Returns success unless a SIGSPEC is invalid or an invalid option is given. | |
726f6388 JA |
57 | $END |
58 | ||
ccc6cda3 JA |
59 | #include <config.h> |
60 | ||
61 | #if defined (HAVE_UNISTD_H) | |
cce855bc JA |
62 | # ifdef _MINIX |
63 | # include <sys/types.h> | |
64 | # endif | |
ccc6cda3 JA |
65 | # include <unistd.h> |
66 | #endif | |
67 | ||
68 | #include "../bashtypes.h" | |
726f6388 | 69 | #include <signal.h> |
ccc6cda3 JA |
70 | #include <stdio.h> |
71 | #include "../bashansi.h" | |
72 | ||
726f6388 JA |
73 | #include "../shell.h" |
74 | #include "../trap.h" | |
75 | #include "common.h" | |
ccc6cda3 JA |
76 | #include "bashgetopt.h" |
77 | ||
f73dda09 JA |
78 | static void showtrap __P((int)); |
79 | static int display_traps __P((WORD_LIST *)); | |
726f6388 JA |
80 | |
81 | /* The trap command: | |
82 | ||
83 | trap <arg> <signal ...> | |
84 | trap <signal ...> | |
85 | trap -l | |
ccc6cda3 | 86 | trap -p [sigspec ...] |
726f6388 JA |
87 | trap [--] |
88 | ||
89 | Set things up so that ARG is executed when SIGNAL(s) N is recieved. | |
90 | If ARG is the empty string, then ignore the SIGNAL(s). If there is | |
91 | no ARG, then set the trap for SIGNAL(s) to its original value. Just | |
92 | plain "trap" means to print out the list of commands associated with | |
93 | each signal number. Single arg of "-l" means list the signal names. */ | |
94 | ||
95 | /* Possible operations to perform on the list of signals.*/ | |
96 | #define SET 0 /* Set this signal to first_arg. */ | |
97 | #define REVERT 1 /* Revert to this signals original value. */ | |
98 | #define IGNORE 2 /* Ignore this signal. */ | |
99 | ||
495aee44 | 100 | extern int posixly_correct, subshell_environment; |
726f6388 | 101 | |
ccc6cda3 | 102 | int |
726f6388 JA |
103 | trap_builtin (list) |
104 | WORD_LIST *list; | |
105 | { | |
0628567a | 106 | int list_signal_names, display, result, opt; |
726f6388 | 107 | |
ccc6cda3 JA |
108 | list_signal_names = display = 0; |
109 | result = EXECUTION_SUCCESS; | |
495aee44 | 110 | |
ccc6cda3 JA |
111 | reset_internal_getopt (); |
112 | while ((opt = internal_getopt (list, "lp")) != -1) | |
726f6388 | 113 | { |
ccc6cda3 | 114 | switch (opt) |
726f6388 | 115 | { |
ccc6cda3 | 116 | case 'l': |
726f6388 | 117 | list_signal_names++; |
726f6388 | 118 | break; |
ccc6cda3 JA |
119 | case 'p': |
120 | display++; | |
121 | break; | |
122 | default: | |
123 | builtin_usage (); | |
726f6388 JA |
124 | return (EX_USAGE); |
125 | } | |
726f6388 | 126 | } |
ccc6cda3 | 127 | list = loptend; |
726f6388 | 128 | |
b80f6443 JA |
129 | opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */ |
130 | ||
726f6388 | 131 | if (list_signal_names) |
3185942a | 132 | return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1))); |
ccc6cda3 | 133 | else if (display || list == 0) |
495aee44 CR |
134 | { |
135 | initialize_terminating_signals (); | |
136 | get_all_original_signals (); | |
137 | return (sh_chkwrite (display_traps (list))); | |
138 | } | |
ccc6cda3 | 139 | else |
726f6388 | 140 | { |
ccc6cda3 | 141 | char *first_arg; |
eb873671 | 142 | int operation, sig, first_signal; |
726f6388 | 143 | |
ccc6cda3 JA |
144 | operation = SET; |
145 | first_arg = list->word->word; | |
eb873671 JA |
146 | first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt); |
147 | ||
0628567a JA |
148 | /* Backwards compatibility. XXX - question about whether or not we |
149 | should throw an error if an all-digit argument doesn't correspond | |
150 | to a valid signal number (e.g., if it's `50' on a system with only | |
151 | 32 signals). */ | |
eb873671 JA |
152 | if (first_signal) |
153 | operation = REVERT; | |
b80f6443 JA |
154 | /* When in posix mode, the historical behavior of looking for a |
155 | missing first argument is disabled. To revert to the original | |
156 | signal handling disposition, use `-' as the first argument. */ | |
eb873671 | 157 | else if (posixly_correct == 0 && first_arg && *first_arg && |
b80f6443 JA |
158 | (*first_arg != '-' || first_arg[1]) && |
159 | signal_object_p (first_arg, opt) && list->next == 0) | |
726f6388 JA |
160 | operation = REVERT; |
161 | else | |
162 | { | |
163 | list = list->next; | |
b80f6443 JA |
164 | if (list == 0) |
165 | { | |
166 | builtin_usage (); | |
167 | return (EX_USAGE); | |
168 | } | |
169 | else if (*first_arg == '\0') | |
726f6388 JA |
170 | operation = IGNORE; |
171 | else if (first_arg[0] == '-' && !first_arg[1]) | |
172 | operation = REVERT; | |
173 | } | |
174 | ||
495aee44 CR |
175 | /* If we're in a command substitution, we haven't freed the trap strings |
176 | (though we reset the signal handlers). If we're setting a trap to | |
177 | handle a signal here, free the rest of the trap strings since they | |
178 | don't apply any more. */ | |
179 | if (subshell_environment & SUBSHELL_RESETTRAP) | |
180 | { | |
181 | free_trap_strings (); | |
182 | subshell_environment &= ~SUBSHELL_RESETTRAP; | |
183 | } | |
184 | ||
726f6388 JA |
185 | while (list) |
186 | { | |
b80f6443 | 187 | sig = decode_signal (list->word->word, opt); |
726f6388 JA |
188 | |
189 | if (sig == NO_SIG) | |
190 | { | |
7117c2d2 | 191 | sh_invalidsig (list->word->word); |
ccc6cda3 | 192 | result = EXECUTION_FAILURE; |
726f6388 JA |
193 | } |
194 | else | |
195 | { | |
196 | switch (operation) | |
197 | { | |
198 | case SET: | |
199 | set_signal (sig, first_arg); | |
200 | break; | |
201 | ||
202 | case REVERT: | |
203 | restore_default_signal (sig); | |
204 | ||
205 | /* Signals that the shell treats specially need special | |
206 | handling. */ | |
207 | switch (sig) | |
208 | { | |
209 | case SIGINT: | |
495aee44 CR |
210 | /* XXX - should we do this if original disposition |
211 | was SIG_IGN? */ | |
726f6388 JA |
212 | if (interactive) |
213 | set_signal_handler (SIGINT, sigint_sighandler); | |
214 | else | |
0628567a | 215 | set_signal_handler (SIGINT, termsig_sighandler); |
726f6388 JA |
216 | break; |
217 | ||
218 | case SIGQUIT: | |
219 | /* Always ignore SIGQUIT. */ | |
220 | set_signal_handler (SIGQUIT, SIG_IGN); | |
221 | break; | |
222 | case SIGTERM: | |
223 | #if defined (JOB_CONTROL) | |
224 | case SIGTTIN: | |
225 | case SIGTTOU: | |
226 | case SIGTSTP: | |
227 | #endif /* JOB_CONTROL */ | |
228 | if (interactive) | |
229 | set_signal_handler (sig, SIG_IGN); | |
230 | break; | |
231 | } | |
232 | break; | |
233 | ||
234 | case IGNORE: | |
235 | ignore_signal (sig); | |
236 | break; | |
237 | } | |
238 | } | |
239 | list = list->next; | |
240 | } | |
726f6388 JA |
241 | } |
242 | ||
ccc6cda3 JA |
243 | return (result); |
244 | } | |
245 | ||
246 | static void | |
247 | showtrap (i) | |
248 | int i; | |
249 | { | |
e8ce775d | 250 | char *t, *p, *sn; |
ccc6cda3 JA |
251 | |
252 | p = trap_list[i]; | |
495aee44 | 253 | if (p == (char *)DEFAULT_SIG && signal_is_hard_ignored (i) == 0) |
ccc6cda3 | 254 | return; |
495aee44 CR |
255 | else if (signal_is_hard_ignored (i)) |
256 | t = (char *)NULL; | |
257 | else | |
258 | t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p); | |
ccc6cda3 | 259 | |
e8ce775d JA |
260 | sn = signal_name (i); |
261 | /* Make sure that signals whose names are unknown (for whatever reason) | |
262 | are printed as signal numbers. */ | |
263 | if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7)) | |
264 | printf ("trap -- %s %d\n", t ? t : "''", i); | |
28ef6c31 JA |
265 | else if (posixly_correct) |
266 | { | |
267 | if (STREQN (sn, "SIG", 3)) | |
268 | printf ("trap -- %s %s\n", t ? t : "''", sn+3); | |
269 | else | |
270 | printf ("trap -- %s %s\n", t ? t : "''", sn); | |
271 | } | |
e8ce775d JA |
272 | else |
273 | printf ("trap -- %s %s\n", t ? t : "''", sn); | |
274 | ||
275 | FREE (t); | |
ccc6cda3 | 276 | } |
726f6388 | 277 | |
ccc6cda3 JA |
278 | static int |
279 | display_traps (list) | |
280 | WORD_LIST *list; | |
281 | { | |
282 | int result, i; | |
726f6388 | 283 | |
ccc6cda3 JA |
284 | if (list == 0) |
285 | { | |
f73dda09 | 286 | for (i = 0; i < BASH_NSIG; i++) |
ccc6cda3 JA |
287 | showtrap (i); |
288 | return (EXECUTION_SUCCESS); | |
289 | } | |
726f6388 | 290 | |
ccc6cda3 JA |
291 | for (result = EXECUTION_SUCCESS; list; list = list->next) |
292 | { | |
b80f6443 | 293 | i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX); |
ccc6cda3 JA |
294 | if (i == NO_SIG) |
295 | { | |
7117c2d2 | 296 | sh_invalidsig (list->word->word); |
ccc6cda3 | 297 | result = EXECUTION_FAILURE; |
ccc6cda3 JA |
298 | } |
299 | else | |
300 | showtrap (i); | |
726f6388 | 301 | } |
ccc6cda3 JA |
302 | |
303 | return (result); | |
726f6388 | 304 | } |