blob: 94229433c50256f92ebe650a9a3ce7c0f1e65617 [file] [log] [blame]
Jari Aalto726f6381996-08-26 18:22:31 +00001This file is trap.def, from which is created trap.c.
2It implements the builtin "trap" in Bash.
3
Chet Ramey74091dd2022-09-26 11:49:46 -04004Copyright (C) 1987-2021 Free Software Foundation, Inc.
Jari Aalto726f6381996-08-26 18:22:31 +00005
6This file is part of GNU Bash, the Bourne Again SHell.
7
Jari Aalto31859422009-01-12 13:36:28 +00008Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
Jari Aalto726f6381996-08-26 18:22:31 +000012
Jari Aalto31859422009-01-12 13:36:28 +000013Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
Jari Aalto726f6381996-08-26 18:22:31 +000017
Jari Aalto31859422009-01-12 13:36:28 +000018You should have received a copy of the GNU General Public License
19along with Bash. If not, see <http://www.gnu.org/licenses/>.
Jari Aalto726f6381996-08-26 18:22:31 +000020
21$PRODUCES trap.c
22
23$BUILTIN trap
24$FUNCTION trap_builtin
Jari Aalto31859422009-01-12 13:36:28 +000025$SHORT_DOC trap [-lp] [[arg] signal_spec ...]
26Trap signals and other events.
27
28Defines and activates handlers to be run when the shell receives signals
29or other conditions.
30
31ARG is a command to be read and executed when the shell receives the
Jari Aaltob80f6442004-07-27 13:29:18 +000032signal(s) SIGNAL_SPEC. If ARG is absent (and a single SIGNAL_SPEC
33is supplied) or `-', each specified signal is reset to its original
34value. If ARG is the null string each SIGNAL_SPEC is ignored by the
Jari Aalto31859422009-01-12 13:36:28 +000035shell and by the commands it invokes.
36
37If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell. If
Chet Ramey495aee42011-11-22 19:11:26 -050038a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command. If
39a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a
40script run by the . or source builtins finishes executing. A SIGNAL_SPEC
41of ERR means to execute ARG each time a command's failure would cause the
42shell to exit when the -e option is enabled.
Jari Aalto31859422009-01-12 13:36:28 +000043
44If no arguments are supplied, trap prints the list of commands associated
45with each signal.
46
47Options:
48 -l print a list of signal names and their corresponding numbers
49 -p display the trap commands associated with each SIGNAL_SPEC
50
51Each SIGNAL_SPEC is either a signal name in <signal.h> or a signal number.
52Signal names are case insensitive and the SIG prefix is optional. A
53signal may be sent to the shell with "kill -signal $$".
54
55Exit Status:
56Returns success unless a SIGSPEC is invalid or an invalid option is given.
Jari Aalto726f6381996-08-26 18:22:31 +000057$END
58
Jari Aaltoccc6cda1996-12-23 17:02:34 +000059#include <config.h>
60
61#if defined (HAVE_UNISTD_H)
Jari Aaltocce855b1998-04-17 19:52:44 +000062# ifdef _MINIX
63# include <sys/types.h>
64# endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +000065# include <unistd.h>
66#endif
67
68#include "../bashtypes.h"
Jari Aalto726f6381996-08-26 18:22:31 +000069#include <signal.h>
Jari Aaltoccc6cda1996-12-23 17:02:34 +000070#include <stdio.h>
71#include "../bashansi.h"
72
Jari Aalto726f6381996-08-26 18:22:31 +000073#include "../shell.h"
74#include "../trap.h"
75#include "common.h"
Jari Aaltoccc6cda1996-12-23 17:02:34 +000076#include "bashgetopt.h"
77
Chet Ramey8868eda2020-12-06 15:51:17 -050078static void showtrap PARAMS((int, int));
79static int display_traps PARAMS((WORD_LIST *, int));
Jari Aalto726f6381996-08-26 18:22:31 +000080
81/* The trap command:
82
83 trap <arg> <signal ...>
84 trap <signal ...>
85 trap -l
Jari Aaltoccc6cda1996-12-23 17:02:34 +000086 trap -p [sigspec ...]
Jari Aalto726f6381996-08-26 18:22:31 +000087 trap [--]
88
Chet Rameya0c0a002016-09-15 16:59:08 -040089 Set things up so that ARG is executed when SIGNAL(s) N is received.
Jari Aalto726f6381996-08-26 18:22:31 +000090 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
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000100int
Jari Aalto726f6381996-08-26 18:22:31 +0000101trap_builtin (list)
102 WORD_LIST *list;
103{
Jari Aalto06285672006-10-10 14:15:34 +0000104 int list_signal_names, display, result, opt;
Jari Aalto726f6381996-08-26 18:22:31 +0000105
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000106 list_signal_names = display = 0;
107 result = EXECUTION_SUCCESS;
Chet Ramey495aee42011-11-22 19:11:26 -0500108
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000109 reset_internal_getopt ();
110 while ((opt = internal_getopt (list, "lp")) != -1)
Jari Aalto726f6381996-08-26 18:22:31 +0000111 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000112 switch (opt)
Jari Aalto726f6381996-08-26 18:22:31 +0000113 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000114 case 'l':
Jari Aalto726f6381996-08-26 18:22:31 +0000115 list_signal_names++;
Jari Aalto726f6381996-08-26 18:22:31 +0000116 break;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000117 case 'p':
118 display++;
119 break;
Chet Rameya0c0a002016-09-15 16:59:08 -0400120 CASE_HELPOPT;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000121 default:
122 builtin_usage ();
Jari Aalto726f6381996-08-26 18:22:31 +0000123 return (EX_USAGE);
124 }
Jari Aalto726f6381996-08-26 18:22:31 +0000125 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000126 list = loptend;
Jari Aalto726f6381996-08-26 18:22:31 +0000127
Jari Aaltob80f6442004-07-27 13:29:18 +0000128 opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */
129
Jari Aalto726f6381996-08-26 18:22:31 +0000130 if (list_signal_names)
Jari Aalto31859422009-01-12 13:36:28 +0000131 return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1)));
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000132 else if (display || list == 0)
Chet Ramey495aee42011-11-22 19:11:26 -0500133 {
134 initialize_terminating_signals ();
135 get_all_original_signals ();
Chet Ramey8868eda2020-12-06 15:51:17 -0500136 return (sh_chkwrite (display_traps (list, display && posixly_correct)));
Chet Ramey495aee42011-11-22 19:11:26 -0500137 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000138 else
Jari Aalto726f6381996-08-26 18:22:31 +0000139 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000140 char *first_arg;
Jari Aaltoeb873672004-11-09 21:37:25 +0000141 int operation, sig, first_signal;
Jari Aalto726f6381996-08-26 18:22:31 +0000142
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000143 operation = SET;
144 first_arg = list->word->word;
Jari Aaltoeb873672004-11-09 21:37:25 +0000145 first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
146
Jari Aalto06285672006-10-10 14:15:34 +0000147 /* Backwards compatibility. XXX - question about whether or not we
148 should throw an error if an all-digit argument doesn't correspond
149 to a valid signal number (e.g., if it's `50' on a system with only
150 32 signals). */
Jari Aaltoeb873672004-11-09 21:37:25 +0000151 if (first_signal)
152 operation = REVERT;
Jari Aaltob80f6442004-07-27 13:29:18 +0000153 /* When in posix mode, the historical behavior of looking for a
154 missing first argument is disabled. To revert to the original
155 signal handling disposition, use `-' as the first argument. */
Jari Aaltoeb873672004-11-09 21:37:25 +0000156 else if (posixly_correct == 0 && first_arg && *first_arg &&
Jari Aaltob80f6442004-07-27 13:29:18 +0000157 (*first_arg != '-' || first_arg[1]) &&
158 signal_object_p (first_arg, opt) && list->next == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000159 operation = REVERT;
160 else
161 {
162 list = list->next;
Jari Aaltob80f6442004-07-27 13:29:18 +0000163 if (list == 0)
164 {
165 builtin_usage ();
166 return (EX_USAGE);
167 }
168 else if (*first_arg == '\0')
Jari Aalto726f6381996-08-26 18:22:31 +0000169 operation = IGNORE;
170 else if (first_arg[0] == '-' && !first_arg[1])
171 operation = REVERT;
172 }
173
Chet Ramey495aee42011-11-22 19:11:26 -0500174 /* If we're in a command substitution, we haven't freed the trap strings
175 (though we reset the signal handlers). If we're setting a trap to
176 handle a signal here, free the rest of the trap strings since they
177 don't apply any more. */
178 if (subshell_environment & SUBSHELL_RESETTRAP)
179 {
180 free_trap_strings ();
181 subshell_environment &= ~SUBSHELL_RESETTRAP;
182 }
183
Jari Aalto726f6381996-08-26 18:22:31 +0000184 while (list)
185 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000186 sig = decode_signal (list->word->word, opt);
Jari Aalto726f6381996-08-26 18:22:31 +0000187
188 if (sig == NO_SIG)
189 {
Jari Aalto7117c2d2002-07-17 14:10:11 +0000190 sh_invalidsig (list->word->word);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000191 result = EXECUTION_FAILURE;
Jari Aalto726f6381996-08-26 18:22:31 +0000192 }
193 else
194 {
195 switch (operation)
196 {
197 case SET:
198 set_signal (sig, first_arg);
199 break;
200
201 case REVERT:
202 restore_default_signal (sig);
203
204 /* Signals that the shell treats specially need special
205 handling. */
206 switch (sig)
207 {
208 case SIGINT:
Chet Ramey495aee42011-11-22 19:11:26 -0500209 /* XXX - should we do this if original disposition
210 was SIG_IGN? */
Jari Aalto726f6381996-08-26 18:22:31 +0000211 if (interactive)
212 set_signal_handler (SIGINT, sigint_sighandler);
Chet Ramey64447602018-06-01 10:22:36 -0400213 /* special cases for interactive == 0 */
Chet Ramey8868eda2020-12-06 15:51:17 -0500214 else if (interactive_shell && (sourcelevel||running_trap||parse_and_execute_level))
Chet Ramey64447602018-06-01 10:22:36 -0400215 set_signal_handler (SIGINT, sigint_sighandler);
Jari Aalto726f6381996-08-26 18:22:31 +0000216 else
Jari Aalto06285672006-10-10 14:15:34 +0000217 set_signal_handler (SIGINT, termsig_sighandler);
Jari Aalto726f6381996-08-26 18:22:31 +0000218 break;
219
220 case SIGQUIT:
221 /* Always ignore SIGQUIT. */
222 set_signal_handler (SIGQUIT, SIG_IGN);
223 break;
224 case SIGTERM:
225#if defined (JOB_CONTROL)
226 case SIGTTIN:
227 case SIGTTOU:
228 case SIGTSTP:
229#endif /* JOB_CONTROL */
230 if (interactive)
231 set_signal_handler (sig, SIG_IGN);
232 break;
233 }
234 break;
235
236 case IGNORE:
237 ignore_signal (sig);
238 break;
239 }
240 }
241 list = list->next;
242 }
Jari Aalto726f6381996-08-26 18:22:31 +0000243 }
244
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000245 return (result);
246}
247
248static void
Chet Ramey8868eda2020-12-06 15:51:17 -0500249showtrap (i, show_default)
250 int i, show_default;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000251{
Jari Aaltoe8ce7751997-09-22 20:22:27 +0000252 char *t, *p, *sn;
Chet Ramey74091dd2022-09-26 11:49:46 -0400253 int free_t;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000254
Chet Ramey74091dd2022-09-26 11:49:46 -0400255 free_t = 1;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000256 p = trap_list[i];
Chet Ramey495aee42011-11-22 19:11:26 -0500257 if (p == (char *)DEFAULT_SIG && signal_is_hard_ignored (i) == 0)
Chet Ramey8868eda2020-12-06 15:51:17 -0500258 {
259 if (show_default)
260 t = "-";
261 else
262 return;
Chet Ramey74091dd2022-09-26 11:49:46 -0400263 free_t = 0;
Chet Ramey8868eda2020-12-06 15:51:17 -0500264 }
Chet Ramey495aee42011-11-22 19:11:26 -0500265 else if (signal_is_hard_ignored (i))
266 t = (char *)NULL;
267 else
268 t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000269
Jari Aaltoe8ce7751997-09-22 20:22:27 +0000270 sn = signal_name (i);
271 /* Make sure that signals whose names are unknown (for whatever reason)
272 are printed as signal numbers. */
273 if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7))
274 printf ("trap -- %s %d\n", t ? t : "''", i);
Jari Aalto28ef6c32001-04-06 19:14:31 +0000275 else if (posixly_correct)
276 {
277 if (STREQN (sn, "SIG", 3))
278 printf ("trap -- %s %s\n", t ? t : "''", sn+3);
279 else
280 printf ("trap -- %s %s\n", t ? t : "''", sn);
281 }
Jari Aaltoe8ce7751997-09-22 20:22:27 +0000282 else
283 printf ("trap -- %s %s\n", t ? t : "''", sn);
284
Chet Ramey74091dd2022-09-26 11:49:46 -0400285 if (free_t)
Chet Ramey8868eda2020-12-06 15:51:17 -0500286 FREE (t);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000287}
288
289static int
Chet Ramey8868eda2020-12-06 15:51:17 -0500290display_traps (list, show_all)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000291 WORD_LIST *list;
Chet Ramey8868eda2020-12-06 15:51:17 -0500292 int show_all;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000293{
294 int result, i;
295
296 if (list == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000297 {
Jari Aaltof73dda02001-11-13 17:56:06 +0000298 for (i = 0; i < BASH_NSIG; i++)
Chet Ramey8868eda2020-12-06 15:51:17 -0500299 showtrap (i, show_all);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000300 return (EXECUTION_SUCCESS);
Jari Aalto726f6381996-08-26 18:22:31 +0000301 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000302
303 for (result = EXECUTION_SUCCESS; list; list = list->next)
304 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000305 i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000306 if (i == NO_SIG)
307 {
Jari Aalto7117c2d2002-07-17 14:10:11 +0000308 sh_invalidsig (list->word->word);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000309 result = EXECUTION_FAILURE;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000310 }
311 else
Chet Ramey8868eda2020-12-06 15:51:17 -0500312 showtrap (i, show_all);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000313 }
314
315 return (result);
Jari Aalto726f6381996-08-26 18:22:31 +0000316}