]>
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 | ||
a0c0a00f | 4 | Copyright (C) 1987-2015 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 | ||
a0c0a00f | 89 | Set things up so that ARG is executed when SIGNAL(s) N is received. |
726f6388 JA |
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; |
64447609 | 101 | extern int sourcelevel, running_trap; |
726f6388 | 102 | |
ccc6cda3 | 103 | int |
726f6388 JA |
104 | trap_builtin (list) |
105 | WORD_LIST *list; | |
106 | { | |
0628567a | 107 | int list_signal_names, display, result, opt; |
726f6388 | 108 | |
ccc6cda3 JA |
109 | list_signal_names = display = 0; |
110 | result = EXECUTION_SUCCESS; | |
495aee44 | 111 | |
ccc6cda3 JA |
112 | reset_internal_getopt (); |
113 | while ((opt = internal_getopt (list, "lp")) != -1) | |
726f6388 | 114 | { |
ccc6cda3 | 115 | switch (opt) |
726f6388 | 116 | { |
ccc6cda3 | 117 | case 'l': |
726f6388 | 118 | list_signal_names++; |
726f6388 | 119 | break; |
ccc6cda3 JA |
120 | case 'p': |
121 | display++; | |
122 | break; | |
a0c0a00f | 123 | CASE_HELPOPT; |
ccc6cda3 JA |
124 | default: |
125 | builtin_usage (); | |
726f6388 JA |
126 | return (EX_USAGE); |
127 | } | |
726f6388 | 128 | } |
ccc6cda3 | 129 | list = loptend; |
726f6388 | 130 | |
b80f6443 JA |
131 | opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */ |
132 | ||
726f6388 | 133 | if (list_signal_names) |
3185942a | 134 | return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1))); |
ccc6cda3 | 135 | else if (display || list == 0) |
495aee44 CR |
136 | { |
137 | initialize_terminating_signals (); | |
138 | get_all_original_signals (); | |
139 | return (sh_chkwrite (display_traps (list))); | |
140 | } | |
ccc6cda3 | 141 | else |
726f6388 | 142 | { |
ccc6cda3 | 143 | char *first_arg; |
eb873671 | 144 | int operation, sig, first_signal; |
726f6388 | 145 | |
ccc6cda3 JA |
146 | operation = SET; |
147 | first_arg = list->word->word; | |
eb873671 JA |
148 | first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt); |
149 | ||
0628567a JA |
150 | /* Backwards compatibility. XXX - question about whether or not we |
151 | should throw an error if an all-digit argument doesn't correspond | |
152 | to a valid signal number (e.g., if it's `50' on a system with only | |
153 | 32 signals). */ | |
eb873671 JA |
154 | if (first_signal) |
155 | operation = REVERT; | |
b80f6443 JA |
156 | /* When in posix mode, the historical behavior of looking for a |
157 | missing first argument is disabled. To revert to the original | |
158 | signal handling disposition, use `-' as the first argument. */ | |
eb873671 | 159 | else if (posixly_correct == 0 && first_arg && *first_arg && |
b80f6443 JA |
160 | (*first_arg != '-' || first_arg[1]) && |
161 | signal_object_p (first_arg, opt) && list->next == 0) | |
726f6388 JA |
162 | operation = REVERT; |
163 | else | |
164 | { | |
165 | list = list->next; | |
b80f6443 JA |
166 | if (list == 0) |
167 | { | |
168 | builtin_usage (); | |
169 | return (EX_USAGE); | |
170 | } | |
171 | else if (*first_arg == '\0') | |
726f6388 JA |
172 | operation = IGNORE; |
173 | else if (first_arg[0] == '-' && !first_arg[1]) | |
174 | operation = REVERT; | |
175 | } | |
176 | ||
495aee44 CR |
177 | /* If we're in a command substitution, we haven't freed the trap strings |
178 | (though we reset the signal handlers). If we're setting a trap to | |
179 | handle a signal here, free the rest of the trap strings since they | |
180 | don't apply any more. */ | |
181 | if (subshell_environment & SUBSHELL_RESETTRAP) | |
182 | { | |
183 | free_trap_strings (); | |
184 | subshell_environment &= ~SUBSHELL_RESETTRAP; | |
185 | } | |
186 | ||
726f6388 JA |
187 | while (list) |
188 | { | |
b80f6443 | 189 | sig = decode_signal (list->word->word, opt); |
726f6388 JA |
190 | |
191 | if (sig == NO_SIG) | |
192 | { | |
7117c2d2 | 193 | sh_invalidsig (list->word->word); |
ccc6cda3 | 194 | result = EXECUTION_FAILURE; |
726f6388 JA |
195 | } |
196 | else | |
197 | { | |
198 | switch (operation) | |
199 | { | |
200 | case SET: | |
201 | set_signal (sig, first_arg); | |
202 | break; | |
203 | ||
204 | case REVERT: | |
205 | restore_default_signal (sig); | |
206 | ||
207 | /* Signals that the shell treats specially need special | |
208 | handling. */ | |
209 | switch (sig) | |
210 | { | |
211 | case SIGINT: | |
495aee44 CR |
212 | /* XXX - should we do this if original disposition |
213 | was SIG_IGN? */ | |
726f6388 JA |
214 | if (interactive) |
215 | set_signal_handler (SIGINT, sigint_sighandler); | |
64447609 CR |
216 | /* special cases for interactive == 0 */ |
217 | else if (interactive_shell && (sourcelevel||running_trap)) | |
218 | set_signal_handler (SIGINT, sigint_sighandler); | |
726f6388 | 219 | else |
0628567a | 220 | set_signal_handler (SIGINT, termsig_sighandler); |
726f6388 JA |
221 | break; |
222 | ||
223 | case SIGQUIT: | |
224 | /* Always ignore SIGQUIT. */ | |
225 | set_signal_handler (SIGQUIT, SIG_IGN); | |
226 | break; | |
227 | case SIGTERM: | |
228 | #if defined (JOB_CONTROL) | |
229 | case SIGTTIN: | |
230 | case SIGTTOU: | |
231 | case SIGTSTP: | |
232 | #endif /* JOB_CONTROL */ | |
233 | if (interactive) | |
234 | set_signal_handler (sig, SIG_IGN); | |
235 | break; | |
236 | } | |
237 | break; | |
238 | ||
239 | case IGNORE: | |
240 | ignore_signal (sig); | |
241 | break; | |
242 | } | |
243 | } | |
244 | list = list->next; | |
245 | } | |
726f6388 JA |
246 | } |
247 | ||
ccc6cda3 JA |
248 | return (result); |
249 | } | |
250 | ||
251 | static void | |
252 | showtrap (i) | |
253 | int i; | |
254 | { | |
e8ce775d | 255 | char *t, *p, *sn; |
ccc6cda3 JA |
256 | |
257 | p = trap_list[i]; | |
495aee44 | 258 | if (p == (char *)DEFAULT_SIG && signal_is_hard_ignored (i) == 0) |
ccc6cda3 | 259 | return; |
495aee44 CR |
260 | else if (signal_is_hard_ignored (i)) |
261 | t = (char *)NULL; | |
262 | else | |
263 | t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p); | |
ccc6cda3 | 264 | |
e8ce775d JA |
265 | sn = signal_name (i); |
266 | /* Make sure that signals whose names are unknown (for whatever reason) | |
267 | are printed as signal numbers. */ | |
268 | if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7)) | |
269 | printf ("trap -- %s %d\n", t ? t : "''", i); | |
28ef6c31 JA |
270 | else if (posixly_correct) |
271 | { | |
272 | if (STREQN (sn, "SIG", 3)) | |
273 | printf ("trap -- %s %s\n", t ? t : "''", sn+3); | |
274 | else | |
275 | printf ("trap -- %s %s\n", t ? t : "''", sn); | |
276 | } | |
e8ce775d JA |
277 | else |
278 | printf ("trap -- %s %s\n", t ? t : "''", sn); | |
279 | ||
280 | FREE (t); | |
ccc6cda3 | 281 | } |
726f6388 | 282 | |
ccc6cda3 JA |
283 | static int |
284 | display_traps (list) | |
285 | WORD_LIST *list; | |
286 | { | |
287 | int result, i; | |
726f6388 | 288 | |
ccc6cda3 JA |
289 | if (list == 0) |
290 | { | |
f73dda09 | 291 | for (i = 0; i < BASH_NSIG; i++) |
ccc6cda3 JA |
292 | showtrap (i); |
293 | return (EXECUTION_SUCCESS); | |
294 | } | |
726f6388 | 295 | |
ccc6cda3 JA |
296 | for (result = EXECUTION_SUCCESS; list; list = list->next) |
297 | { | |
b80f6443 | 298 | i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX); |
ccc6cda3 JA |
299 | if (i == NO_SIG) |
300 | { | |
7117c2d2 | 301 | sh_invalidsig (list->word->word); |
ccc6cda3 | 302 | result = EXECUTION_FAILURE; |
ccc6cda3 JA |
303 | } |
304 | else | |
305 | showtrap (i); | |
726f6388 | 306 | } |
ccc6cda3 JA |
307 | |
308 | return (result); | |
726f6388 | 309 | } |