Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /*- |
2 | * Copyright (c) 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Kenneth Almquist. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. All advertising materials mentioning features or use of this software | |
17 | * must display the following acknowledgement: | |
18 | * This product includes software developed by the University of | |
19 | * California, Berkeley and its contributors. | |
20 | * 4. Neither the name of the University nor the names of its contributors | |
21 | * may be used to endorse or promote products derived from this software | |
22 | * without specific prior written permission. | |
23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | */ | |
36 | ||
37 | #ifndef lint | |
38 | static char sccsid[] = "@(#)trap.c 5.2 (Berkeley) 4/12/91"; | |
39 | #endif /* not lint */ | |
40 | ||
41 | #include "shell.h" | |
42 | #include "main.h" | |
43 | #include "nodes.h" /* for other headers */ | |
44 | #include "eval.h" | |
45 | #include "jobs.h" | |
46 | #include "options.h" | |
47 | #include "syntax.h" | |
48 | #include "signames.h" | |
49 | #include "output.h" | |
50 | #include "memalloc.h" | |
51 | #include "error.h" | |
52 | #include "trap.h" | |
53 | #include "mystring.h" | |
54 | #include <signal.h> | |
55 | ||
56 | ||
57 | /* | |
58 | * Sigmode records the current value of the signal handlers for the various | |
59 | * modes. A value of zero means that the current handler is not known. | |
60 | * S_HARD_IGN indicates that the signal was ignored on entry to the shell, | |
61 | */ | |
62 | ||
63 | #define S_DFL 1 /* default signal handling (SIG_DFL) */ | |
64 | #define S_CATCH 2 /* signal is caught */ | |
65 | #define S_IGN 3 /* signal is ignored (SIG_IGN) */ | |
66 | #define S_HARD_IGN 4 /* signal is ignored permenantly */ | |
67 | ||
68 | ||
69 | extern char nullstr[1]; /* null string */ | |
70 | ||
71 | char *trap[MAXSIG+1]; /* trap handler commands */ | |
72 | MKINIT char sigmode[MAXSIG]; /* current value of signal */ | |
73 | char gotsig[MAXSIG]; /* indicates specified signal received */ | |
74 | int pendingsigs; /* indicates some signal received */ | |
75 | ||
76 | /* | |
77 | * The trap builtin. | |
78 | */ | |
79 | ||
80 | trapcmd(argc, argv) char **argv; { | |
81 | char *action; | |
82 | char **ap; | |
83 | int signo; | |
84 | ||
85 | if (argc <= 1) { | |
86 | for (signo = 0 ; signo <= MAXSIG ; signo++) { | |
87 | if (trap[signo] != NULL) | |
88 | out1fmt("%d: %s\n", signo, trap[signo]); | |
89 | } | |
90 | return 0; | |
91 | } | |
92 | ap = argv + 1; | |
93 | if (is_number(*ap)) | |
94 | action = NULL; | |
95 | else | |
96 | action = *ap++; | |
97 | while (*ap) { | |
98 | if ((signo = number(*ap)) < 0 || signo > MAXSIG) | |
99 | error("%s: bad trap", *ap); | |
100 | INTOFF; | |
101 | if (action) | |
102 | action = savestr(action); | |
103 | if (trap[signo]) | |
104 | ckfree(trap[signo]); | |
105 | trap[signo] = action; | |
106 | if (signo != 0) | |
107 | setsignal(signo); | |
108 | INTON; | |
109 | ap++; | |
110 | } | |
111 | return 0; | |
112 | } | |
113 | ||
114 | ||
115 | ||
116 | /* | |
117 | * Clear traps on a fork. | |
118 | */ | |
119 | ||
120 | void | |
121 | clear_traps() { | |
122 | char **tp; | |
123 | ||
124 | for (tp = trap ; tp <= &trap[MAXSIG] ; tp++) { | |
125 | if (*tp && **tp) { /* trap not NULL or SIG_IGN */ | |
126 | INTOFF; | |
127 | ckfree(*tp); | |
128 | *tp = NULL; | |
129 | if (tp != &trap[0]) | |
130 | setsignal(tp - trap); | |
131 | INTON; | |
132 | } | |
133 | } | |
134 | } | |
135 | ||
136 | ||
137 | ||
138 | /* | |
139 | * Set the signal handler for the specified signal. The routine figures | |
140 | * out what it should be set to. | |
141 | */ | |
142 | ||
143 | int | |
144 | setsignal(signo) { | |
145 | int action; | |
146 | sig_t sigact; | |
147 | char *t; | |
148 | extern void onsig(); | |
149 | ||
150 | if ((t = trap[signo]) == NULL) | |
151 | action = S_DFL; | |
152 | else if (*t != '\0') | |
153 | action = S_CATCH; | |
154 | else | |
155 | action = S_IGN; | |
156 | if (rootshell && action == S_DFL) { | |
157 | switch (signo) { | |
158 | case SIGINT: | |
159 | if (iflag) | |
160 | action = S_CATCH; | |
161 | break; | |
162 | case SIGQUIT: | |
163 | #ifdef DEBUG | |
164 | { | |
165 | extern int debug; | |
166 | ||
167 | if (debug) | |
168 | break; | |
169 | } | |
170 | #endif | |
171 | /* FALLTHROUGH */ | |
172 | case SIGTERM: | |
173 | if (iflag) | |
174 | action = S_IGN; | |
175 | break; | |
176 | #if JOBS | |
177 | case SIGTSTP: | |
178 | case SIGTTOU: | |
179 | if (jflag) | |
180 | action = S_IGN; | |
181 | break; | |
182 | #endif | |
183 | } | |
184 | } | |
185 | t = &sigmode[signo - 1]; | |
186 | if (*t == 0) { /* current setting unknown */ | |
187 | /* | |
188 | * There is a race condition here if action is not S_IGN. | |
189 | * A signal can be ignored that shouldn't be. | |
190 | */ | |
191 | if ((int)(sigact = signal(signo, SIG_IGN)) == -1) | |
192 | error("Signal system call failed"); | |
193 | if (sigact == SIG_IGN) { | |
194 | *t = S_HARD_IGN; | |
195 | } else { | |
196 | *t = S_IGN; | |
197 | } | |
198 | } | |
199 | if (*t == S_HARD_IGN || *t == action) | |
200 | return 0; | |
201 | switch (action) { | |
202 | case S_DFL: sigact = SIG_DFL; break; | |
203 | case S_CATCH: sigact = onsig; break; | |
204 | case S_IGN: sigact = SIG_IGN; break; | |
205 | } | |
206 | *t = action; | |
207 | return (int)signal(signo, sigact); | |
208 | } | |
209 | ||
210 | ||
211 | /* | |
212 | * Ignore a signal. | |
213 | */ | |
214 | ||
215 | void | |
216 | ignoresig(signo) { | |
217 | if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { | |
218 | signal(signo, SIG_IGN); | |
219 | } | |
220 | sigmode[signo - 1] = S_HARD_IGN; | |
221 | } | |
222 | ||
223 | ||
224 | #ifdef mkinit | |
225 | INCLUDE "signames.h" | |
226 | INCLUDE "trap.h" | |
227 | ||
228 | SHELLPROC { | |
229 | char *sm; | |
230 | ||
231 | clear_traps(); | |
232 | for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) { | |
233 | if (*sm == S_IGN) | |
234 | *sm = S_HARD_IGN; | |
235 | } | |
236 | } | |
237 | #endif | |
238 | ||
239 | ||
240 | ||
241 | /* | |
242 | * Signal handler. | |
243 | */ | |
244 | ||
245 | void | |
246 | onsig(signo) { | |
247 | signal(signo, onsig); | |
248 | if (signo == SIGINT && trap[SIGINT] == NULL) { | |
249 | onint(); | |
250 | return; | |
251 | } | |
252 | gotsig[signo - 1] = 1; | |
253 | pendingsigs++; | |
254 | } | |
255 | ||
256 | ||
257 | ||
258 | /* | |
259 | * Called to execute a trap. Perhaps we should avoid entering new trap | |
260 | * handlers while we are executing a trap handler. | |
261 | */ | |
262 | ||
263 | void | |
264 | dotrap() { | |
265 | int i; | |
266 | int savestatus; | |
267 | ||
268 | for (;;) { | |
269 | for (i = 1 ; ; i++) { | |
270 | if (gotsig[i - 1]) | |
271 | break; | |
272 | if (i >= MAXSIG) | |
273 | goto done; | |
274 | } | |
275 | gotsig[i - 1] = 0; | |
276 | savestatus=exitstatus; | |
277 | evalstring(trap[i]); | |
278 | exitstatus=savestatus; | |
279 | } | |
280 | done: | |
281 | pendingsigs = 0; | |
282 | } | |
283 | ||
284 | ||
285 | ||
286 | /* | |
287 | * Controls whether the shell is interactive or not. | |
288 | */ | |
289 | ||
290 | int is_interactive; | |
291 | ||
292 | void | |
293 | setinteractive(on) { | |
294 | if (on == is_interactive) | |
295 | return; | |
296 | setsignal(SIGINT); | |
297 | setsignal(SIGQUIT); | |
298 | setsignal(SIGTERM); | |
299 | is_interactive = on; | |
300 | } | |
301 | ||
302 | ||
303 | ||
304 | /* | |
305 | * Called to exit the shell. | |
306 | */ | |
307 | ||
308 | void | |
309 | exitshell(status) { | |
310 | struct jmploc loc1, loc2; | |
311 | char *p; | |
312 | ||
313 | TRACE(("exitshell(%d) pid=%d\n", status, getpid())); | |
314 | if (setjmp(loc1.loc)) goto l1; | |
315 | if (setjmp(loc2.loc)) goto l2; | |
316 | handler = &loc1; | |
317 | if ((p = trap[0]) != NULL && *p != '\0') { | |
318 | trap[0] = NULL; | |
319 | evalstring(p); | |
320 | } | |
321 | l1: handler = &loc2; /* probably unnecessary */ | |
322 | flushall(); | |
323 | #if JOBS | |
324 | setjobctl(0); | |
325 | #endif | |
326 | l2: _exit(status); | |
327 | } |