Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 1 | This file is trap.def, from which is created trap.c. |
| 2 | It implements the builtin "trap" in Bash. |
| 3 | |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 4 | Copyright (C) 1987-2010 Free Software Foundation, Inc. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 5 | |
| 6 | This file is part of GNU Bash, the Bourne Again SHell. |
| 7 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 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. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 12 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 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. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 17 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 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/>. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 20 | |
| 21 | $PRODUCES trap.c |
| 22 | |
| 23 | $BUILTIN trap |
| 24 | $FUNCTION trap_builtin |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 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 |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 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 |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 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 |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 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. |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 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. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 57 | $END |
| 58 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 59 | #include <config.h> |
| 60 | |
| 61 | #if defined (HAVE_UNISTD_H) |
Jari Aalto | cce855b | 1998-04-17 19:52:44 +0000 | [diff] [blame] | 62 | # ifdef _MINIX |
| 63 | # include <sys/types.h> |
| 64 | # endif |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 65 | # include <unistd.h> |
| 66 | #endif |
| 67 | |
| 68 | #include "../bashtypes.h" |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 69 | #include <signal.h> |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 70 | #include <stdio.h> |
| 71 | #include "../bashansi.h" |
| 72 | |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 73 | #include "../shell.h" |
| 74 | #include "../trap.h" |
| 75 | #include "common.h" |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 76 | #include "bashgetopt.h" |
| 77 | |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 78 | static void showtrap __P((int)); |
| 79 | static int display_traps __P((WORD_LIST *)); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 80 | |
| 81 | /* The trap command: |
| 82 | |
| 83 | trap <arg> <signal ...> |
| 84 | trap <signal ...> |
| 85 | trap -l |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 86 | trap -p [sigspec ...] |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 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 | |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 100 | extern int posixly_correct, subshell_environment; |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 101 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 102 | int |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 103 | trap_builtin (list) |
| 104 | WORD_LIST *list; |
| 105 | { |
Jari Aalto | 0628567 | 2006-10-10 14:15:34 +0000 | [diff] [blame] | 106 | int list_signal_names, display, result, opt; |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 107 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 108 | list_signal_names = display = 0; |
| 109 | result = EXECUTION_SUCCESS; |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 110 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 111 | reset_internal_getopt (); |
| 112 | while ((opt = internal_getopt (list, "lp")) != -1) |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 113 | { |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 114 | switch (opt) |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 115 | { |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 116 | case 'l': |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 117 | list_signal_names++; |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 118 | break; |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 119 | case 'p': |
| 120 | display++; |
| 121 | break; |
| 122 | default: |
| 123 | builtin_usage (); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 124 | return (EX_USAGE); |
| 125 | } |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 126 | } |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 127 | list = loptend; |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 128 | |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 129 | opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */ |
| 130 | |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 131 | if (list_signal_names) |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 132 | return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1))); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 133 | else if (display || list == 0) |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 134 | { |
| 135 | initialize_terminating_signals (); |
| 136 | get_all_original_signals (); |
| 137 | return (sh_chkwrite (display_traps (list))); |
| 138 | } |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 139 | else |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 140 | { |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 141 | char *first_arg; |
Jari Aalto | eb87367 | 2004-11-09 21:37:25 +0000 | [diff] [blame] | 142 | int operation, sig, first_signal; |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 143 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 144 | operation = SET; |
| 145 | first_arg = list->word->word; |
Jari Aalto | eb87367 | 2004-11-09 21:37:25 +0000 | [diff] [blame] | 146 | first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt); |
| 147 | |
Jari Aalto | 0628567 | 2006-10-10 14:15:34 +0000 | [diff] [blame] | 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). */ |
Jari Aalto | eb87367 | 2004-11-09 21:37:25 +0000 | [diff] [blame] | 152 | if (first_signal) |
| 153 | operation = REVERT; |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 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. */ |
Jari Aalto | eb87367 | 2004-11-09 21:37:25 +0000 | [diff] [blame] | 157 | else if (posixly_correct == 0 && first_arg && *first_arg && |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 158 | (*first_arg != '-' || first_arg[1]) && |
| 159 | signal_object_p (first_arg, opt) && list->next == 0) |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 160 | operation = REVERT; |
| 161 | else |
| 162 | { |
| 163 | list = list->next; |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 164 | if (list == 0) |
| 165 | { |
| 166 | builtin_usage (); |
| 167 | return (EX_USAGE); |
| 168 | } |
| 169 | else if (*first_arg == '\0') |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 170 | operation = IGNORE; |
| 171 | else if (first_arg[0] == '-' && !first_arg[1]) |
| 172 | operation = REVERT; |
| 173 | } |
| 174 | |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 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 | |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 185 | while (list) |
| 186 | { |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 187 | sig = decode_signal (list->word->word, opt); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 188 | |
| 189 | if (sig == NO_SIG) |
| 190 | { |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 191 | sh_invalidsig (list->word->word); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 192 | result = EXECUTION_FAILURE; |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 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: |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 210 | /* XXX - should we do this if original disposition |
| 211 | was SIG_IGN? */ |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 212 | if (interactive) |
| 213 | set_signal_handler (SIGINT, sigint_sighandler); |
| 214 | else |
Jari Aalto | 0628567 | 2006-10-10 14:15:34 +0000 | [diff] [blame] | 215 | set_signal_handler (SIGINT, termsig_sighandler); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 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 | } |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 241 | } |
| 242 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 243 | return (result); |
| 244 | } |
| 245 | |
| 246 | static void |
| 247 | showtrap (i) |
| 248 | int i; |
| 249 | { |
Jari Aalto | e8ce775 | 1997-09-22 20:22:27 +0000 | [diff] [blame] | 250 | char *t, *p, *sn; |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 251 | |
| 252 | p = trap_list[i]; |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 253 | if (p == (char *)DEFAULT_SIG && signal_is_hard_ignored (i) == 0) |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 254 | return; |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 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); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 259 | |
Jari Aalto | e8ce775 | 1997-09-22 20:22:27 +0000 | [diff] [blame] | 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); |
Jari Aalto | 28ef6c3 | 2001-04-06 19:14:31 +0000 | [diff] [blame] | 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 | } |
Jari Aalto | e8ce775 | 1997-09-22 20:22:27 +0000 | [diff] [blame] | 272 | else |
| 273 | printf ("trap -- %s %s\n", t ? t : "''", sn); |
| 274 | |
| 275 | FREE (t); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 276 | } |
| 277 | |
| 278 | static int |
| 279 | display_traps (list) |
| 280 | WORD_LIST *list; |
| 281 | { |
| 282 | int result, i; |
| 283 | |
| 284 | if (list == 0) |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 285 | { |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 286 | for (i = 0; i < BASH_NSIG; i++) |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 287 | showtrap (i); |
| 288 | return (EXECUTION_SUCCESS); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 289 | } |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 290 | |
| 291 | for (result = EXECUTION_SUCCESS; list; list = list->next) |
| 292 | { |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 293 | i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 294 | if (i == NO_SIG) |
| 295 | { |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 296 | sh_invalidsig (list->word->word); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 297 | result = EXECUTION_FAILURE; |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 298 | } |
| 299 | else |
| 300 | showtrap (i); |
| 301 | } |
| 302 | |
| 303 | return (result); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 304 | } |