| @@ -1,596 +1,598 @@ | | | @@ -1,596 +1,598 @@ |
1 | /* $NetBSD: trap.c,v 1.40.2.1 2017/07/23 14:58:14 snj Exp $ */ | | 1 | /* $NetBSD: trap.c,v 1.40.2.2 2018/08/25 14:41:21 martin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1991, 1993 | | 4 | * Copyright (c) 1991, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Kenneth Almquist. | | 8 | * Kenneth Almquist. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of the University nor the names of its contributors | | 18 | * 3. Neither the name of the University nor the names of its contributors |
19 | * may be used to endorse or promote products derived from this software | | 19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. | | 20 | * without specific prior written permission. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. | | 32 | * SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | #ifndef lint | | 36 | #ifndef lint |
37 | #if 0 | | 37 | #if 0 |
38 | static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; | | 38 | static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; |
39 | #else | | 39 | #else |
40 | __RCSID("$NetBSD: trap.c,v 1.40.2.1 2017/07/23 14:58:14 snj Exp $"); | | 40 | __RCSID("$NetBSD: trap.c,v 1.40.2.2 2018/08/25 14:41:21 martin Exp $"); |
41 | #endif | | 41 | #endif |
42 | #endif /* not lint */ | | 42 | #endif /* not lint */ |
43 | | | 43 | |
44 | #include <signal.h> | | 44 | #include <signal.h> |
45 | #include <unistd.h> | | 45 | #include <unistd.h> |
46 | #include <stdlib.h> | | 46 | #include <stdlib.h> |
47 | #include <stdio.h> | | 47 | #include <stdio.h> |
48 | | | 48 | |
49 | #include "shell.h" | | 49 | #include "shell.h" |
50 | #include "main.h" | | 50 | #include "main.h" |
51 | #include "nodes.h" /* for other headers */ | | 51 | #include "nodes.h" /* for other headers */ |
52 | #include "eval.h" | | 52 | #include "eval.h" |
53 | #include "jobs.h" | | 53 | #include "jobs.h" |
54 | #include "show.h" | | 54 | #include "show.h" |
55 | #include "options.h" | | 55 | #include "options.h" |
56 | #include "builtins.h" | | 56 | #include "builtins.h" |
57 | #include "syntax.h" | | 57 | #include "syntax.h" |
58 | #include "output.h" | | 58 | #include "output.h" |
59 | #include "memalloc.h" | | 59 | #include "memalloc.h" |
60 | #include "error.h" | | 60 | #include "error.h" |
61 | #include "trap.h" | | 61 | #include "trap.h" |
62 | #include "mystring.h" | | 62 | #include "mystring.h" |
63 | #include "var.h" | | 63 | #include "var.h" |
64 | | | 64 | |
65 | | | 65 | |
66 | /* | | 66 | /* |
67 | * Sigmode records the current value of the signal handlers for the various | | 67 | * Sigmode records the current value of the signal handlers for the various |
68 | * modes. A value of zero means that the current handler is not known. | | 68 | * modes. A value of zero means that the current handler is not known. |
69 | * S_HARD_IGN indicates that the signal was ignored on entry to the shell, | | 69 | * S_HARD_IGN indicates that the signal was ignored on entry to the shell, |
70 | */ | | 70 | */ |
71 | | | 71 | |
72 | #define S_DFL 1 /* default signal handling (SIG_DFL) */ | | 72 | #define S_DFL 1 /* default signal handling (SIG_DFL) */ |
73 | #define S_CATCH 2 /* signal is caught */ | | 73 | #define S_CATCH 2 /* signal is caught */ |
74 | #define S_IGN 3 /* signal is ignored (SIG_IGN) */ | | 74 | #define S_IGN 3 /* signal is ignored (SIG_IGN) */ |
75 | #define S_HARD_IGN 4 /* signal is ignored permenantly */ | | 75 | #define S_HARD_IGN 4 /* signal is ignored permenantly */ |
76 | #define S_RESET 5 /* temporary - to reset a hard ignored sig */ | | 76 | #define S_RESET 5 /* temporary - to reset a hard ignored sig */ |
77 | | | 77 | |
78 | | | 78 | |
79 | char *trap[NSIG]; /* trap handler commands */ | | 79 | char *trap[NSIG]; /* trap handler commands */ |
80 | MKINIT char sigmode[NSIG]; /* current value of signal */ | | 80 | MKINIT char sigmode[NSIG]; /* current value of signal */ |
81 | static volatile char gotsig[NSIG];/* indicates specified signal received */ | | 81 | static volatile char gotsig[NSIG];/* indicates specified signal received */ |
82 | volatile int pendingsigs; /* indicates some signal received */ | | 82 | volatile int pendingsigs; /* indicates some signal received */ |
83 | | | 83 | |
84 | static int getsigaction(int, sig_t *); | | 84 | static int getsigaction(int, sig_t *); |
85 | STATIC const char *trap_signame(int); | | 85 | STATIC const char *trap_signame(int); |
86 | | | 86 | |
87 | /* | | 87 | /* |
88 | * return the signal number described by `p' (as a number or a name) | | 88 | * return the signal number described by `p' (as a number or a name) |
89 | * or -1 if it isn't one | | 89 | * or -1 if it isn't one |
90 | */ | | 90 | */ |
91 | | | 91 | |
92 | static int | | 92 | static int |
93 | signame_to_signum(const char *p) | | 93 | signame_to_signum(const char *p) |
94 | { | | 94 | { |
95 | int i; | | 95 | int i; |
96 | | | 96 | |
97 | if (is_number(p)) | | 97 | if (is_number(p)) |
98 | return number(p); | | 98 | return number(p); |
99 | | | 99 | |
100 | if (strcasecmp(p, "exit") == 0 ) | | 100 | if (strcasecmp(p, "exit") == 0 ) |
101 | return 0; | | 101 | return 0; |
102 | | | 102 | |
103 | if (strncasecmp(p, "sig", 3) == 0) | | 103 | if (strncasecmp(p, "sig", 3) == 0) |
104 | p += 3; | | 104 | p += 3; |
105 | | | 105 | |
106 | for (i = 0; i < NSIG; ++i) | | 106 | for (i = 0; i < NSIG; ++i) |
107 | if (strcasecmp (p, sys_signame[i]) == 0) | | 107 | if (strcasecmp (p, sys_signame[i]) == 0) |
108 | return i; | | 108 | return i; |
109 | return -1; | | 109 | return -1; |
110 | } | | 110 | } |
111 | | | 111 | |
112 | /* | | 112 | /* |
113 | * return the name of a signal used by the "trap" command | | 113 | * return the name of a signal used by the "trap" command |
114 | */ | | 114 | */ |
115 | STATIC const char * | | 115 | STATIC const char * |
116 | trap_signame(int signo) | | 116 | trap_signame(int signo) |
117 | { | | 117 | { |
118 | static char nbuf[12]; | | 118 | static char nbuf[12]; |
119 | const char *p = NULL; | | 119 | const char *p = NULL; |
120 | | | 120 | |
121 | if (signo == 0) | | 121 | if (signo == 0) |
122 | return "EXIT"; | | 122 | return "EXIT"; |
123 | if (signo > 0 && signo < NSIG) | | 123 | if (signo > 0 && signo < NSIG) |
124 | p = sys_signame[signo]; | | 124 | p = sys_signame[signo]; |
125 | if (p != NULL) | | 125 | if (p != NULL) |
126 | return p; | | 126 | return p; |
127 | (void)snprintf(nbuf, sizeof nbuf, "%d", signo); | | 127 | (void)snprintf(nbuf, sizeof nbuf, "%d", signo); |
128 | return nbuf; | | 128 | return nbuf; |
129 | } | | 129 | } |
130 | | | 130 | |
131 | /* | | 131 | /* |
132 | * Print a list of valid signal names | | 132 | * Print a list of valid signal names |
133 | */ | | 133 | */ |
134 | static void | | 134 | static void |
135 | printsignals(void) | | 135 | printsignals(void) |
136 | { | | 136 | { |
137 | int n; | | 137 | int n; |
138 | | | 138 | |
139 | out1str("EXIT "); | | 139 | out1str("EXIT "); |
140 | | | 140 | |
141 | for (n = 1; n < NSIG; n++) { | | 141 | for (n = 1; n < NSIG; n++) { |
142 | out1fmt("%s", trap_signame(n)); | | 142 | out1fmt("%s", trap_signame(n)); |
143 | if ((n == NSIG/2) || n == (NSIG - 1)) | | 143 | if ((n == NSIG/2) || n == (NSIG - 1)) |
144 | out1str("\n"); | | 144 | out1str("\n"); |
145 | else | | 145 | else |
146 | out1c(' '); | | 146 | out1c(' '); |
147 | } | | 147 | } |
148 | } | | 148 | } |
149 | | | 149 | |
150 | /* | | 150 | /* |
151 | * The trap builtin. | | 151 | * The trap builtin. |
152 | */ | | 152 | */ |
153 | | | 153 | |
154 | int | | 154 | int |
155 | trapcmd(int argc, char **argv) | | 155 | trapcmd(int argc, char **argv) |
156 | { | | 156 | { |
157 | char *action; | | 157 | char *action; |
158 | char **ap; | | 158 | char **ap; |
159 | int signo; | | 159 | int signo; |
160 | int errs = 0; | | 160 | int errs = 0; |
161 | int printonly = 0; | | 161 | int printonly = 0; |
162 | | | 162 | |
163 | ap = argv + 1; | | 163 | ap = argv + 1; |
164 | | | 164 | |
165 | if (argc == 2 && strcmp(*ap, "-l") == 0) { | | 165 | if (argc == 2 && strcmp(*ap, "-l") == 0) { |
166 | printsignals(); | | 166 | printsignals(); |
167 | return 0; | | 167 | return 0; |
168 | } | | 168 | } |
169 | if (argc == 2 && strcmp(*ap, "-") == 0) { | | 169 | if (argc == 2 && strcmp(*ap, "-") == 0) { |
170 | for (signo = 0; signo < NSIG; signo++) { | | 170 | for (signo = 0; signo < NSIG; signo++) { |
171 | if (trap[signo] == NULL) | | 171 | if (trap[signo] == NULL) |
172 | continue; | | 172 | continue; |
173 | INTOFF; | | 173 | INTOFF; |
174 | ckfree(trap[signo]); | | 174 | ckfree(trap[signo]); |
175 | trap[signo] = NULL; | | 175 | trap[signo] = NULL; |
176 | if (signo != 0) | | 176 | if (signo != 0) |
177 | setsignal(signo, 0); | | 177 | setsignal(signo, 0); |
178 | INTON; | | 178 | INTON; |
179 | } | | 179 | } |
180 | return 0; | | 180 | return 0; |
181 | } | | 181 | } |
182 | if (argc >= 2 && strcmp(*ap, "-p") == 0) { | | 182 | if (argc >= 2 && strcmp(*ap, "-p") == 0) { |
183 | printonly = 1; | | 183 | printonly = 1; |
184 | ap++; | | 184 | ap++; |
185 | argc--; | | 185 | argc--; |
186 | } | | 186 | } |
187 | | | 187 | |
188 | if (argc > 1 && strcmp(*ap, "--") == 0) { | | 188 | if (argc > 1 && strcmp(*ap, "--") == 0) { |
189 | argc--; | | 189 | argc--; |
190 | ap++; | | 190 | ap++; |
191 | } | | 191 | } |
192 | | | 192 | |
193 | if (argc <= 1) { | | 193 | if (argc <= 1) { |
194 | int count; | | 194 | int count; |
195 | | | 195 | |
196 | if (printonly) { | | 196 | if (printonly) { |
197 | for (count = 0, signo = 0 ; signo < NSIG ; signo++) | | 197 | for (count = 0, signo = 0 ; signo < NSIG ; signo++) |
198 | if (trap[signo] == NULL) { | | 198 | if (trap[signo] == NULL) { |
199 | if (count == 0) | | 199 | if (count == 0) |
200 | out1str("trap -- -"); | | 200 | out1str("trap -- -"); |
201 | out1fmt(" %s", trap_signame(signo)); | | 201 | out1fmt(" %s", trap_signame(signo)); |
202 | /* oh! unlucky 13 */ | | 202 | /* oh! unlucky 13 */ |
203 | if (++count >= 13) { | | 203 | if (++count >= 13) { |
204 | out1str("\n"); | | 204 | out1str("\n"); |
205 | count = 0; | | 205 | count = 0; |
206 | } | | 206 | } |
207 | } | | 207 | } |
208 | if (count) | | 208 | if (count) |
209 | out1str("\n"); | | 209 | out1str("\n"); |
210 | } | | 210 | } |
211 | | | 211 | |
212 | for (count = 0, signo = 0 ; signo < NSIG ; signo++) | | 212 | for (count = 0, signo = 0 ; signo < NSIG ; signo++) |
213 | if (trap[signo] != NULL && trap[signo][0] == '\0') { | | 213 | if (trap[signo] != NULL && trap[signo][0] == '\0') { |
214 | if (count == 0) | | 214 | if (count == 0) |
215 | out1str("trap -- ''"); | | 215 | out1str("trap -- ''"); |
216 | out1fmt(" %s", trap_signame(signo)); | | 216 | out1fmt(" %s", trap_signame(signo)); |
217 | /* | | 217 | /* |
218 | * the prefix is 10 bytes, with 4 byte | | 218 | * the prefix is 10 bytes, with 4 byte |
219 | * signal names (common) we have room in | | 219 | * signal names (common) we have room in |
220 | * the 70 bytes left on a normal line for | | 220 | * the 70 bytes left on a normal line for |
221 | * 70/(4+1) signals, that's 14, but to | | 221 | * 70/(4+1) signals, that's 14, but to |
222 | * allow for the occasional longer sig name | | 222 | * allow for the occasional longer sig name |
223 | * we output one less... | | 223 | * we output one less... |
224 | */ | | 224 | */ |
225 | if (++count >= 13) { | | 225 | if (++count >= 13) { |
226 | out1str("\n"); | | 226 | out1str("\n"); |
227 | count = 0; | | 227 | count = 0; |
228 | } | | 228 | } |
229 | } | | 229 | } |
230 | if (count) | | 230 | if (count) |
231 | out1str("\n"); | | 231 | out1str("\n"); |
232 | | | 232 | |
233 | for (signo = 0 ; signo < NSIG ; signo++) | | 233 | for (signo = 0 ; signo < NSIG ; signo++) |
234 | if (trap[signo] != NULL && trap[signo][0] != '\0') { | | 234 | if (trap[signo] != NULL && trap[signo][0] != '\0') { |
235 | out1str("trap -- "); | | 235 | out1str("trap -- "); |
236 | print_quoted(trap[signo]); | | 236 | print_quoted(trap[signo]); |
237 | out1fmt(" %s\n", trap_signame(signo)); | | 237 | out1fmt(" %s\n", trap_signame(signo)); |
238 | } | | 238 | } |
239 | | | 239 | |
240 | return 0; | | 240 | return 0; |
241 | } | | 241 | } |
242 | | | 242 | |
243 | action = NULL; | | 243 | action = NULL; |
244 | | | 244 | |
245 | if (!printonly && !is_number(*ap)) { | | 245 | if (!printonly && !is_number(*ap)) { |
246 | if ((*ap)[0] == '-' && (*ap)[1] == '\0') | | 246 | if ((*ap)[0] == '-' && (*ap)[1] == '\0') |
247 | ap++; /* reset to default */ | | 247 | ap++; /* reset to default */ |
248 | else | | 248 | else |
249 | action = *ap++; /* can be '' for "ignore" */ | | 249 | action = *ap++; /* can be '' for "ignore" */ |
250 | argc--; | | 250 | argc--; |
251 | } | | 251 | } |
252 | | | 252 | |
253 | if (argc < 2) { /* there must be at least 1 condition */ | | 253 | if (argc < 2) { /* there must be at least 1 condition */ |
254 | out2str("Usage: trap [-l]\n" | | 254 | out2str("Usage: trap [-l]\n" |
255 | " trap -p [condition ...]\n" | | 255 | " trap -p [condition ...]\n" |
256 | " trap action condition ...\n" | | 256 | " trap action condition ...\n" |
257 | " trap N condition ...\n"); | | 257 | " trap N condition ...\n"); |
258 | return 2; | | 258 | return 2; |
259 | } | | 259 | } |
260 | | | 260 | |
261 | | | 261 | |
262 | while (*ap) { | | 262 | while (*ap) { |
263 | signo = signame_to_signum(*ap); | | 263 | signo = signame_to_signum(*ap); |
264 | | | 264 | |
265 | if (signo < 0 || signo >= NSIG) { | | 265 | if (signo < 0 || signo >= NSIG) { |
266 | /* This is not a fatal error, so sayeth posix */ | | 266 | /* This is not a fatal error, so sayeth posix */ |
267 | outfmt(out2, "trap: '%s' bad condition\n", *ap); | | 267 | outfmt(out2, "trap: '%s' bad condition\n", *ap); |
268 | errs = 1; | | 268 | errs = 1; |
269 | ap++; | | 269 | ap++; |
270 | continue; | | 270 | continue; |
271 | } | | 271 | } |
272 | ap++; | | 272 | ap++; |
273 | | | 273 | |
274 | if (printonly) { | | 274 | if (printonly) { |
275 | out1str("trap -- "); | | 275 | out1str("trap -- "); |
276 | if (trap[signo] == NULL) | | 276 | if (trap[signo] == NULL) |
277 | out1str("-"); | | 277 | out1str("-"); |
278 | else | | 278 | else |
279 | print_quoted(trap[signo]); | | 279 | print_quoted(trap[signo]); |
280 | out1fmt(" %s\n", trap_signame(signo)); | | 280 | out1fmt(" %s\n", trap_signame(signo)); |
281 | continue; | | 281 | continue; |
282 | } | | 282 | } |
283 | | | 283 | |
284 | INTOFF; | | 284 | INTOFF; |
285 | if (action) | | 285 | if (action) |
286 | action = savestr(action); | | 286 | action = savestr(action); |
287 | | | 287 | |
288 | if (trap[signo]) | | 288 | if (trap[signo]) |
289 | ckfree(trap[signo]); | | 289 | ckfree(trap[signo]); |
290 | | | 290 | |
291 | trap[signo] = action; | | 291 | trap[signo] = action; |
292 | | | 292 | |
293 | if (signo != 0) | | 293 | if (signo != 0) |
294 | setsignal(signo, 0); | | 294 | setsignal(signo, 0); |
295 | INTON; | | 295 | INTON; |
296 | } | | 296 | } |
297 | return errs; | | 297 | return errs; |
298 | } | | 298 | } |
299 | | | 299 | |
300 | | | 300 | |
301 | | | 301 | |
302 | /* | | 302 | /* |
303 | * Clear traps on a fork or vfork. | | 303 | * Clear traps on a fork or vfork. |
304 | * Takes one arg vfork, to tell it to not be destructive of | | 304 | * Takes one arg vfork, to tell it to not be destructive of |
305 | * the parents variables. | | 305 | * the parents variables. |
306 | */ | | 306 | */ |
307 | | | 307 | |
308 | void | | 308 | void |
309 | clear_traps(int vforked) | | 309 | clear_traps(int vforked) |
310 | { | | 310 | { |
311 | char **tp; | | 311 | char **tp; |
312 | | | 312 | |
313 | for (tp = trap ; tp < &trap[NSIG] ; tp++) { | | 313 | for (tp = trap ; tp < &trap[NSIG] ; tp++) { |
314 | if (*tp && **tp) { /* trap not NULL or SIG_IGN */ | | 314 | if (*tp && **tp) { /* trap not NULL or SIG_IGN */ |
315 | INTOFF; | | 315 | INTOFF; |
316 | if (!vforked) { | | 316 | if (!vforked) { |
317 | ckfree(*tp); | | 317 | ckfree(*tp); |
318 | *tp = NULL; | | 318 | *tp = NULL; |
319 | } | | 319 | } |
320 | if (tp != &trap[0]) | | 320 | if (tp != &trap[0]) |
321 | setsignal(tp - trap, vforked); | | 321 | setsignal(tp - trap, vforked); |
322 | INTON; | | 322 | INTON; |
323 | } | | 323 | } |
324 | } | | 324 | } |
325 | } | | 325 | } |
326 | | | 326 | |
327 | | | 327 | |
328 | | | 328 | |
329 | /* | | 329 | /* |
330 | * Set the signal handler for the specified signal. The routine figures | | 330 | * Set the signal handler for the specified signal. The routine figures |
331 | * out what it should be set to. | | 331 | * out what it should be set to. |
332 | */ | | 332 | */ |
333 | | | 333 | |
334 | sig_t | | 334 | sig_t |
335 | setsignal(int signo, int vforked) | | 335 | setsignal(int signo, int vforked) |
336 | { | | 336 | { |
337 | int action; | | 337 | int action; |
338 | sig_t sigact = SIG_DFL, sig; | | 338 | sig_t sigact = SIG_DFL, sig; |
339 | char *t, tsig; | | 339 | char *t, tsig; |
340 | | | 340 | |
341 | if ((t = trap[signo]) == NULL) | | 341 | if ((t = trap[signo]) == NULL) |
342 | action = S_DFL; | | 342 | action = S_DFL; |
343 | else if (*t != '\0') | | 343 | else if (*t != '\0') |
344 | action = S_CATCH; | | 344 | action = S_CATCH; |
345 | else | | 345 | else |
346 | action = S_IGN; | | 346 | action = S_IGN; |
347 | if (rootshell && !vforked && action == S_DFL) { | | 347 | if (rootshell && !vforked && action == S_DFL) { |
348 | switch (signo) { | | 348 | switch (signo) { |
349 | case SIGINT: | | 349 | case SIGINT: |
350 | if (iflag || minusc || sflag == 0) | | 350 | if (iflag || minusc || sflag == 0) |
351 | action = S_CATCH; | | 351 | action = S_CATCH; |
352 | break; | | 352 | break; |
353 | case SIGQUIT: | | 353 | case SIGQUIT: |
354 | #ifdef DEBUG | | 354 | #ifdef DEBUG |
355 | if (debug) | | 355 | if (debug) |
356 | break; | | 356 | break; |
357 | #endif | | 357 | #endif |
358 | /* FALLTHROUGH */ | | 358 | /* FALLTHROUGH */ |
359 | case SIGTERM: | | 359 | case SIGTERM: |
360 | if (iflag) | | 360 | if (iflag) |
361 | action = S_IGN; | | 361 | action = S_IGN; |
362 | break; | | 362 | break; |
363 | #if JOBS | | 363 | #if JOBS |
364 | case SIGTSTP: | | 364 | case SIGTSTP: |
365 | case SIGTTOU: | | 365 | case SIGTTOU: |
366 | if (mflag) | | 366 | if (mflag) |
367 | action = S_IGN; | | 367 | action = S_IGN; |
368 | break; | | 368 | break; |
369 | #endif | | 369 | #endif |
370 | } | | 370 | } |
371 | } | | 371 | } |
372 | | | 372 | |
373 | t = &sigmode[signo - 1]; | | 373 | t = &sigmode[signo - 1]; |
374 | tsig = *t; | | 374 | tsig = *t; |
375 | if (tsig == 0) { | | 375 | if (tsig == 0) { |
376 | /* | | 376 | /* |
377 | * current setting unknown | | 377 | * current setting unknown |
378 | */ | | 378 | */ |
379 | if (!getsigaction(signo, &sigact)) { | | 379 | if (!getsigaction(signo, &sigact)) { |
380 | /* | | 380 | /* |
381 | * Pretend it worked; maybe we should give a warning | | 381 | * Pretend it worked; maybe we should give a warning |
382 | * here, but other shells don't. We don't alter | | 382 | * here, but other shells don't. We don't alter |
383 | * sigmode, so that we retry every time. | | 383 | * sigmode, so that we retry every time. |
384 | */ | | 384 | */ |
385 | return 0; | | 385 | return 0; |
386 | } | | 386 | } |
387 | if (sigact == SIG_IGN) { | | 387 | if (sigact == SIG_IGN) { |
388 | /* | | 388 | /* |
389 | * POSIX 3.14.13 states that non-interactive shells | | 389 | * POSIX 3.14.13 states that non-interactive shells |
390 | * should ignore trap commands for signals that were | | 390 | * should ignore trap commands for signals that were |
391 | * ignored upon entry, and leaves the behavior | | 391 | * ignored upon entry, and leaves the behavior |
392 | * unspecified for interactive shells. On interactive | | 392 | * unspecified for interactive shells. On interactive |
393 | * shells, or if job control is on, and we have a job | | 393 | * shells, or if job control is on, and we have a job |
394 | * control related signal, we allow the trap to work. | | 394 | * control related signal, we allow the trap to work. |
395 | * | | 395 | * |
396 | * This change allows us to be POSIX compliant, and | | 396 | * This change allows us to be POSIX compliant, and |
397 | * at the same time override the default behavior if | | 397 | * at the same time override the default behavior if |
398 | * we need to by setting the interactive flag. | | 398 | * we need to by setting the interactive flag. |
399 | */ | | 399 | */ |
400 | if ((mflag && (signo == SIGTSTP || | | 400 | if ((mflag && (signo == SIGTSTP || |
401 | signo == SIGTTIN || signo == SIGTTOU)) || iflag) { | | 401 | signo == SIGTTIN || signo == SIGTTOU)) || iflag) { |
402 | tsig = S_IGN; | | 402 | tsig = S_IGN; |
403 | } else | | 403 | } else |
404 | tsig = S_HARD_IGN; | | 404 | tsig = S_HARD_IGN; |
405 | } else { | | 405 | } else { |
406 | tsig = S_RESET; /* force to be set */ | | 406 | tsig = S_RESET; /* force to be set */ |
407 | } | | 407 | } |
408 | } | | 408 | } |
409 | if (tsig == S_HARD_IGN || tsig == action) | | 409 | if (tsig == S_HARD_IGN || tsig == action) |
410 | return 0; | | 410 | return 0; |
411 | switch (action) { | | 411 | switch (action) { |
412 | case S_DFL: sigact = SIG_DFL; break; | | 412 | case S_DFL: sigact = SIG_DFL; break; |
413 | case S_CATCH: sigact = onsig; break; | | 413 | case S_CATCH: sigact = onsig; break; |
414 | case S_IGN: sigact = SIG_IGN; break; | | 414 | case S_IGN: sigact = SIG_IGN; break; |
415 | } | | 415 | } |
416 | sig = signal(signo, sigact); | | 416 | sig = signal(signo, sigact); |
417 | if (sig != SIG_ERR) { | | 417 | if (sig != SIG_ERR) { |
418 | sigset_t ss; | | 418 | sigset_t ss; |
419 | if (!vforked) | | 419 | if (!vforked) |
420 | *t = action; | | 420 | *t = action; |
421 | if (action == S_CATCH) | | 421 | if (action == S_CATCH) |
422 | (void)siginterrupt(signo, 1); | | 422 | (void)siginterrupt(signo, 1); |
423 | /* | | 423 | /* |
424 | * If our parent accidentally blocked signals for | | 424 | * If our parent accidentally blocked signals for |
425 | * us make sure we unblock them | | 425 | * us make sure we unblock them |
426 | */ | | 426 | */ |
427 | (void)sigemptyset(&ss); | | 427 | (void)sigemptyset(&ss); |
428 | (void)sigaddset(&ss, signo); | | 428 | (void)sigaddset(&ss, signo); |
429 | (void)sigprocmask(SIG_UNBLOCK, &ss, NULL); | | 429 | (void)sigprocmask(SIG_UNBLOCK, &ss, NULL); |
430 | } | | 430 | } |
431 | return sig; | | 431 | return sig; |
432 | } | | 432 | } |
433 | | | 433 | |
434 | /* | | 434 | /* |
435 | * Return the current setting for sig w/o changing it. | | 435 | * Return the current setting for sig w/o changing it. |
436 | */ | | 436 | */ |
437 | static int | | 437 | static int |
438 | getsigaction(int signo, sig_t *sigact) | | 438 | getsigaction(int signo, sig_t *sigact) |
439 | { | | 439 | { |
440 | struct sigaction sa; | | 440 | struct sigaction sa; |
441 | | | 441 | |
442 | if (sigaction(signo, (struct sigaction *)0, &sa) == -1) | | 442 | if (sigaction(signo, (struct sigaction *)0, &sa) == -1) |
443 | return 0; | | 443 | return 0; |
444 | *sigact = (sig_t) sa.sa_handler; | | 444 | *sigact = (sig_t) sa.sa_handler; |
445 | return 1; | | 445 | return 1; |
446 | } | | 446 | } |
447 | | | 447 | |
448 | /* | | 448 | /* |
449 | * Ignore a signal. | | 449 | * Ignore a signal. |
450 | */ | | 450 | */ |
451 | | | 451 | |
452 | void | | 452 | void |
453 | ignoresig(int signo, int vforked) | | 453 | ignoresig(int signo, int vforked) |
454 | { | | 454 | { |
455 | if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { | | 455 | if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { |
456 | signal(signo, SIG_IGN); | | 456 | signal(signo, SIG_IGN); |
457 | } | | 457 | } |
458 | if (!vforked) | | 458 | if (!vforked) |
459 | sigmode[signo - 1] = S_HARD_IGN; | | 459 | sigmode[signo - 1] = S_HARD_IGN; |
460 | } | | 460 | } |
461 | | | 461 | |
462 | | | 462 | |
463 | #ifdef mkinit | | 463 | #ifdef mkinit |
464 | INCLUDE <signal.h> | | 464 | INCLUDE <signal.h> |
465 | INCLUDE "trap.h" | | 465 | INCLUDE "trap.h" |
466 | | | 466 | |
467 | SHELLPROC { | | 467 | SHELLPROC { |
468 | char *sm; | | 468 | char *sm; |
469 | | | 469 | |
470 | clear_traps(0); | | 470 | clear_traps(0); |
471 | for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { | | 471 | for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { |
472 | if (*sm == S_IGN) | | 472 | if (*sm == S_IGN) |
473 | *sm = S_HARD_IGN; | | 473 | *sm = S_HARD_IGN; |
474 | } | | 474 | } |
475 | } | | 475 | } |
476 | #endif | | 476 | #endif |
477 | | | 477 | |
478 | | | 478 | |
479 | | | 479 | |
480 | /* | | 480 | /* |
481 | * Signal handler. | | 481 | * Signal handler. |
482 | */ | | 482 | */ |
483 | | | 483 | |
484 | void | | 484 | void |
485 | onsig(int signo) | | 485 | onsig(int signo) |
486 | { | | 486 | { |
487 | CTRACE(DBG_SIG, ("Signal %d, had: pending %d, gotsig[%d]=%d\n", | | 487 | CTRACE(DBG_SIG, ("Signal %d, had: pending %d, gotsig[%d]=%d\n", |
488 | signo, pendingsigs, signo, gotsig[signo])); | | 488 | signo, pendingsigs, signo, gotsig[signo])); |
489 | | | 489 | |
490 | signal(signo, onsig); | | 490 | signal(signo, onsig); |
491 | if (signo == SIGINT && trap[SIGINT] == NULL) { | | 491 | if (signo == SIGINT && trap[SIGINT] == NULL) { |
492 | onint(); | | 492 | onint(); |
493 | return; | | 493 | return; |
494 | } | | 494 | } |
495 | gotsig[signo] = 1; | | 495 | gotsig[signo] = 1; |
496 | pendingsigs++; | | 496 | pendingsigs++; |
497 | } | | 497 | } |
498 | | | 498 | |
499 | | | 499 | |
500 | | | 500 | |
501 | /* | | 501 | /* |
502 | * Called to execute a trap. Perhaps we should avoid entering new trap | | 502 | * Called to execute a trap. Perhaps we should avoid entering new trap |
503 | * handlers while we are executing a trap handler. | | 503 | * handlers while we are executing a trap handler. |
504 | */ | | 504 | */ |
505 | | | 505 | |
506 | void | | 506 | void |
507 | dotrap(void) | | 507 | dotrap(void) |
508 | { | | 508 | { |
509 | int i; | | 509 | int i; |
510 | int savestatus; | | 510 | int savestatus; |
511 | char *tr; | | 511 | char *tr; |
512 | | | 512 | |
513 | for (;;) { | | 513 | for (;;) { |
514 | for (i = 1 ; ; i++) { | | 514 | for (i = 1 ; ; i++) { |
515 | if (i >= NSIG) { | | 515 | if (i >= NSIG) { |
516 | pendingsigs = 0; | | 516 | pendingsigs = 0; |
517 | return; | | 517 | return; |
518 | } | | 518 | } |
519 | if (gotsig[i]) | | 519 | if (gotsig[i]) |
520 | break; | | 520 | break; |
521 | } | | 521 | } |
522 | gotsig[i] = 0; | | 522 | gotsig[i] = 0; |
523 | savestatus=exitstatus; | | 523 | savestatus=exitstatus; |
524 | CTRACE(DBG_TRAP|DBG_SIG, ("dotrap %d: \"%s\"\n", i, | | 524 | CTRACE(DBG_TRAP|DBG_SIG, ("dotrap %d: \"%s\"\n", i, |
525 | trap[i] ? trap[i] : "-NULL-")); | | 525 | trap[i] ? trap[i] : "-NULL-")); |
526 | tr = savestr(trap[i]); /* trap code may free trap[i] */ | | 526 | if ((tr = trap[i]) != NULL) { |
527 | evalstring(tr, 0); | | 527 | tr = savestr(tr); /* trap code may free trap[i] */ |
528 | ckfree(tr); | | 528 | evalstring(tr, 0); |
| | | 529 | ckfree(tr); |
| | | 530 | } |
529 | exitstatus=savestatus; | | 531 | exitstatus=savestatus; |
530 | } | | 532 | } |
531 | } | | 533 | } |
532 | | | 534 | |
533 | int | | 535 | int |
534 | lastsig(void) | | 536 | lastsig(void) |
535 | { | | 537 | { |
536 | int i; | | 538 | int i; |
537 | | | 539 | |
538 | for (i = NSIG; --i > 0; ) | | 540 | for (i = NSIG; --i > 0; ) |
539 | if (gotsig[i]) | | 541 | if (gotsig[i]) |
540 | return i; | | 542 | return i; |
541 | return SIGINT; /* XXX */ | | 543 | return SIGINT; /* XXX */ |
542 | } | | 544 | } |
543 | | | 545 | |
544 | /* | | 546 | /* |
545 | * Controls whether the shell is interactive or not. | | 547 | * Controls whether the shell is interactive or not. |
546 | */ | | 548 | */ |
547 | | | 549 | |
548 | | | 550 | |
549 | void | | 551 | void |
550 | setinteractive(int on) | | 552 | setinteractive(int on) |
551 | { | | 553 | { |
552 | static int is_interactive; | | 554 | static int is_interactive; |
553 | | | 555 | |
554 | if (on == is_interactive) | | 556 | if (on == is_interactive) |
555 | return; | | 557 | return; |
556 | setsignal(SIGINT, 0); | | 558 | setsignal(SIGINT, 0); |
557 | setsignal(SIGQUIT, 0); | | 559 | setsignal(SIGQUIT, 0); |
558 | setsignal(SIGTERM, 0); | | 560 | setsignal(SIGTERM, 0); |
559 | is_interactive = on; | | 561 | is_interactive = on; |
560 | } | | 562 | } |
561 | | | 563 | |
562 | | | 564 | |
563 | | | 565 | |
564 | /* | | 566 | /* |
565 | * Called to exit the shell. | | 567 | * Called to exit the shell. |
566 | */ | | 568 | */ |
567 | | | 569 | |
568 | void | | 570 | void |
569 | exitshell(int status) | | 571 | exitshell(int status) |
570 | { | | 572 | { |
571 | struct jmploc loc1, loc2; | | 573 | struct jmploc loc1, loc2; |
572 | char *p; | | 574 | char *p; |
573 | | | 575 | |
574 | CTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP, | | 576 | CTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP, |
575 | ("pid %d, exitshell(%d)\n", getpid(), status)); | | 577 | ("pid %d, exitshell(%d)\n", getpid(), status)); |
576 | | | 578 | |
577 | if (setjmp(loc1.loc)) { | | 579 | if (setjmp(loc1.loc)) { |
578 | goto l1; | | 580 | goto l1; |
579 | } | | 581 | } |
580 | if (setjmp(loc2.loc)) { | | 582 | if (setjmp(loc2.loc)) { |
581 | goto l2; | | 583 | goto l2; |
582 | } | | 584 | } |
583 | handler = &loc1; | | 585 | handler = &loc1; |
584 | if ((p = trap[0]) != NULL && *p != '\0') { | | 586 | if ((p = trap[0]) != NULL && *p != '\0') { |
585 | trap[0] = NULL; | | 587 | trap[0] = NULL; |
586 | VTRACE(DBG_TRAP, ("exit trap: \"%s\"\n", p)); | | 588 | VTRACE(DBG_TRAP, ("exit trap: \"%s\"\n", p)); |
587 | evalstring(p, 0); | | 589 | evalstring(p, 0); |
588 | } | | 590 | } |
589 | l1: handler = &loc2; /* probably unnecessary */ | | 591 | l1: handler = &loc2; /* probably unnecessary */ |
590 | flushall(); | | 592 | flushall(); |
591 | #if JOBS | | 593 | #if JOBS |
592 | setjobctl(0); | | 594 | setjobctl(0); |
593 | #endif | | 595 | #endif |
594 | l2: _exit(status); | | 596 | l2: _exit(status); |
595 | /* NOTREACHED */ | | 597 | /* NOTREACHED */ |
596 | } | | 598 | } |