Dan Pasanen | c6e3786 | 2014-10-02 14:08:59 -0500 | [diff] [blame] | 1 | /* trap.c, created from trap.def. */ |
| 2 | #line 22 "./trap.def" |
| 3 | |
| 4 | #line 58 "./trap.def" |
| 5 | |
| 6 | #include <config.h> |
| 7 | |
| 8 | #if defined (HAVE_UNISTD_H) |
| 9 | # ifdef _MINIX |
| 10 | # include <sys/types.h> |
| 11 | # endif |
| 12 | # include <unistd.h> |
| 13 | #endif |
| 14 | |
| 15 | #include "../bashtypes.h" |
| 16 | #include <signal.h> |
| 17 | #include <stdio.h> |
| 18 | #include "../bashansi.h" |
| 19 | |
| 20 | #include "../shell.h" |
| 21 | #include "../trap.h" |
| 22 | #include "common.h" |
| 23 | #include "bashgetopt.h" |
| 24 | |
| 25 | static void showtrap __P((int)); |
| 26 | static int display_traps __P((WORD_LIST *)); |
| 27 | |
| 28 | /* The trap command: |
| 29 | |
| 30 | trap <arg> <signal ...> |
| 31 | trap <signal ...> |
| 32 | trap -l |
| 33 | trap -p [sigspec ...] |
| 34 | trap [--] |
| 35 | |
| 36 | Set things up so that ARG is executed when SIGNAL(s) N is recieved. |
| 37 | If ARG is the empty string, then ignore the SIGNAL(s). If there is |
| 38 | no ARG, then set the trap for SIGNAL(s) to its original value. Just |
| 39 | plain "trap" means to print out the list of commands associated with |
| 40 | each signal number. Single arg of "-l" means list the signal names. */ |
| 41 | |
| 42 | /* Possible operations to perform on the list of signals.*/ |
| 43 | #define SET 0 /* Set this signal to first_arg. */ |
| 44 | #define REVERT 1 /* Revert to this signals original value. */ |
| 45 | #define IGNORE 2 /* Ignore this signal. */ |
| 46 | |
| 47 | extern int posixly_correct, subshell_environment; |
| 48 | |
| 49 | int |
| 50 | trap_builtin (list) |
| 51 | WORD_LIST *list; |
| 52 | { |
| 53 | int list_signal_names, display, result, opt; |
| 54 | |
| 55 | list_signal_names = display = 0; |
| 56 | result = EXECUTION_SUCCESS; |
| 57 | |
| 58 | reset_internal_getopt (); |
| 59 | while ((opt = internal_getopt (list, "lp")) != -1) |
| 60 | { |
| 61 | switch (opt) |
| 62 | { |
| 63 | case 'l': |
| 64 | list_signal_names++; |
| 65 | break; |
| 66 | case 'p': |
| 67 | display++; |
| 68 | break; |
| 69 | default: |
| 70 | builtin_usage (); |
| 71 | return (EX_USAGE); |
| 72 | } |
| 73 | } |
| 74 | list = loptend; |
| 75 | |
| 76 | opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */ |
| 77 | |
| 78 | if (list_signal_names) |
| 79 | return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1))); |
| 80 | else if (display || list == 0) |
| 81 | { |
| 82 | initialize_terminating_signals (); |
| 83 | get_all_original_signals (); |
| 84 | return (sh_chkwrite (display_traps (list))); |
| 85 | } |
| 86 | else |
| 87 | { |
| 88 | char *first_arg; |
| 89 | int operation, sig, first_signal; |
| 90 | |
| 91 | operation = SET; |
| 92 | first_arg = list->word->word; |
| 93 | first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt); |
| 94 | |
| 95 | /* Backwards compatibility. XXX - question about whether or not we |
| 96 | should throw an error if an all-digit argument doesn't correspond |
| 97 | to a valid signal number (e.g., if it's `50' on a system with only |
| 98 | 32 signals). */ |
| 99 | if (first_signal) |
| 100 | operation = REVERT; |
| 101 | /* When in posix mode, the historical behavior of looking for a |
| 102 | missing first argument is disabled. To revert to the original |
| 103 | signal handling disposition, use `-' as the first argument. */ |
| 104 | else if (posixly_correct == 0 && first_arg && *first_arg && |
| 105 | (*first_arg != '-' || first_arg[1]) && |
| 106 | signal_object_p (first_arg, opt) && list->next == 0) |
| 107 | operation = REVERT; |
| 108 | else |
| 109 | { |
| 110 | list = list->next; |
| 111 | if (list == 0) |
| 112 | { |
| 113 | builtin_usage (); |
| 114 | return (EX_USAGE); |
| 115 | } |
| 116 | else if (*first_arg == '\0') |
| 117 | operation = IGNORE; |
| 118 | else if (first_arg[0] == '-' && !first_arg[1]) |
| 119 | operation = REVERT; |
| 120 | } |
| 121 | |
| 122 | /* If we're in a command substitution, we haven't freed the trap strings |
| 123 | (though we reset the signal handlers). If we're setting a trap to |
| 124 | handle a signal here, free the rest of the trap strings since they |
| 125 | don't apply any more. */ |
| 126 | if (subshell_environment & SUBSHELL_RESETTRAP) |
| 127 | { |
| 128 | free_trap_strings (); |
| 129 | subshell_environment &= ~SUBSHELL_RESETTRAP; |
| 130 | } |
| 131 | |
| 132 | while (list) |
| 133 | { |
| 134 | sig = decode_signal (list->word->word, opt); |
| 135 | |
| 136 | if (sig == NO_SIG) |
| 137 | { |
| 138 | sh_invalidsig (list->word->word); |
| 139 | result = EXECUTION_FAILURE; |
| 140 | } |
| 141 | else |
| 142 | { |
| 143 | switch (operation) |
| 144 | { |
| 145 | case SET: |
| 146 | set_signal (sig, first_arg); |
| 147 | break; |
| 148 | |
| 149 | case REVERT: |
| 150 | restore_default_signal (sig); |
| 151 | |
| 152 | /* Signals that the shell treats specially need special |
| 153 | handling. */ |
| 154 | switch (sig) |
| 155 | { |
| 156 | case SIGINT: |
| 157 | /* XXX - should we do this if original disposition |
| 158 | was SIG_IGN? */ |
| 159 | if (interactive) |
| 160 | set_signal_handler (SIGINT, sigint_sighandler); |
| 161 | else |
| 162 | set_signal_handler (SIGINT, termsig_sighandler); |
| 163 | break; |
| 164 | |
| 165 | case SIGQUIT: |
| 166 | /* Always ignore SIGQUIT. */ |
| 167 | set_signal_handler (SIGQUIT, SIG_IGN); |
| 168 | break; |
| 169 | case SIGTERM: |
| 170 | #if defined (JOB_CONTROL) |
| 171 | case SIGTTIN: |
| 172 | case SIGTTOU: |
| 173 | case SIGTSTP: |
| 174 | #endif /* JOB_CONTROL */ |
| 175 | if (interactive) |
| 176 | set_signal_handler (sig, SIG_IGN); |
| 177 | break; |
| 178 | } |
| 179 | break; |
| 180 | |
| 181 | case IGNORE: |
| 182 | ignore_signal (sig); |
| 183 | break; |
| 184 | } |
| 185 | } |
| 186 | list = list->next; |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | return (result); |
| 191 | } |
| 192 | |
| 193 | static void |
| 194 | showtrap (i) |
| 195 | int i; |
| 196 | { |
| 197 | char *t, *p, *sn; |
| 198 | |
| 199 | p = trap_list[i]; |
| 200 | if (p == (char *)DEFAULT_SIG && signal_is_hard_ignored (i) == 0) |
| 201 | return; |
| 202 | else if (signal_is_hard_ignored (i)) |
| 203 | t = (char *)NULL; |
| 204 | else |
| 205 | t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p); |
| 206 | |
| 207 | sn = signal_name (i); |
| 208 | /* Make sure that signals whose names are unknown (for whatever reason) |
| 209 | are printed as signal numbers. */ |
| 210 | if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7)) |
| 211 | printf ("trap -- %s %d\n", t ? t : "''", i); |
| 212 | else if (posixly_correct) |
| 213 | { |
| 214 | if (STREQN (sn, "SIG", 3)) |
| 215 | printf ("trap -- %s %s\n", t ? t : "''", sn+3); |
| 216 | else |
| 217 | printf ("trap -- %s %s\n", t ? t : "''", sn); |
| 218 | } |
| 219 | else |
| 220 | printf ("trap -- %s %s\n", t ? t : "''", sn); |
| 221 | |
| 222 | FREE (t); |
| 223 | } |
| 224 | |
| 225 | static int |
| 226 | display_traps (list) |
| 227 | WORD_LIST *list; |
| 228 | { |
| 229 | int result, i; |
| 230 | |
| 231 | if (list == 0) |
| 232 | { |
| 233 | for (i = 0; i < BASH_NSIG; i++) |
| 234 | showtrap (i); |
| 235 | return (EXECUTION_SUCCESS); |
| 236 | } |
| 237 | |
| 238 | for (result = EXECUTION_SUCCESS; list; list = list->next) |
| 239 | { |
| 240 | i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX); |
| 241 | if (i == NO_SIG) |
| 242 | { |
| 243 | sh_invalidsig (list->word->word); |
| 244 | result = EXECUTION_FAILURE; |
| 245 | } |
| 246 | else |
| 247 | showtrap (i); |
| 248 | } |
| 249 | |
| 250 | return (result); |
| 251 | } |