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