trap.c revision 1.6 1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. 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 8.1 (Berkeley) 5/31/93";
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 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
68
69
70 extern char nullstr[1]; /* null string */
71
72 char *trap[MAXSIG+1]; /* trap handler commands */
73 MKINIT char sigmode[MAXSIG]; /* current value of signal */
74 char gotsig[MAXSIG]; /* indicates specified signal received */
75 int pendingsigs; /* indicates some signal received */
76
77 /*
78 * The trap builtin.
79 */
80
81 trapcmd(argc, argv) char **argv; {
82 char *action;
83 char **ap;
84 int signo;
85
86 if (argc <= 1) {
87 for (signo = 0 ; signo <= MAXSIG ; signo++) {
88 if (trap[signo] != NULL)
89 out1fmt("%d: %s\n", signo, trap[signo]);
90 }
91 return 0;
92 }
93 ap = argv + 1;
94 if (is_number(*ap))
95 action = NULL;
96 else
97 action = *ap++;
98 while (*ap) {
99 if ((signo = number(*ap)) < 0 || signo > MAXSIG)
100 error("%s: bad trap", *ap);
101 INTOFF;
102 if (action)
103 action = savestr(action);
104 if (trap[signo])
105 ckfree(trap[signo]);
106 trap[signo] = action;
107 if (signo != 0)
108 setsignal(signo);
109 INTON;
110 ap++;
111 }
112 return 0;
113 }
114
115
116
117 /*
118 * Clear traps on a fork.
119 */
120
121 void
122 clear_traps() {
123 char **tp;
124
125 for (tp = trap ; tp <= &trap[MAXSIG] ; tp++) {
126 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
127 INTOFF;
128 ckfree(*tp);
129 *tp = NULL;
130 if (tp != &trap[0])
131 setsignal(tp - trap);
132 INTON;
133 }
134 }
135 }
136
137
138
139 /*
140 * Set the signal handler for the specified signal. The routine figures
141 * out what it should be set to.
142 */
143
144 int
145 setsignal(signo) {
146 int action;
147 sig_t sigact;
148 char *t;
149 extern void onsig();
150 extern sig_t getsigaction();
151
152 if ((t = trap[signo]) == NULL)
153 action = S_DFL;
154 else if (*t != '\0')
155 action = S_CATCH;
156 else
157 action = S_IGN;
158 if (rootshell && action == S_DFL) {
159 switch (signo) {
160 case SIGINT:
161 if (iflag)
162 action = S_CATCH;
163 break;
164 case SIGQUIT:
165 #ifdef DEBUG
166 {
167 extern int debug;
168
169 if (debug)
170 break;
171 }
172 #endif
173 /* FALLTHROUGH */
174 case SIGTERM:
175 if (iflag)
176 action = S_IGN;
177 break;
178 #if JOBS
179 case SIGTSTP:
180 case SIGTTOU:
181 if (mflag)
182 action = S_IGN;
183 break;
184 #endif
185 }
186 }
187 t = &sigmode[signo - 1];
188 if (*t == 0) {
189 /*
190 * current setting unknown
191 */
192 sigact = getsigaction(signo);
193 if (sigact == SIG_IGN) {
194 if (mflag && (signo == SIGTSTP ||
195 signo == SIGTTIN || signo == SIGTTOU)) {
196 *t = S_IGN; /* don't hard ignore these */
197 } else
198 *t = S_HARD_IGN;
199 } else {
200 *t = S_RESET; /* force to be set */
201 }
202 }
203 if (*t == S_HARD_IGN || *t == action)
204 return 0;
205 switch (action) {
206 case S_DFL: sigact = SIG_DFL; break;
207 case S_CATCH: sigact = onsig; break;
208 case S_IGN: sigact = SIG_IGN; break;
209 }
210 *t = action;
211 return (int)signal(signo, sigact);
212 }
213
214 /*
215 * Return the current setting for sig w/o changing it.
216 */
217 sig_t
218 getsigaction(signo) {
219 struct sigaction sa;
220
221 if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
222 error("Sigaction system call failed");
223
224 return sa.sa_handler;
225 }
226
227 /*
228 * Ignore a signal.
229 */
230
231 void
232 ignoresig(signo) {
233 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
234 signal(signo, SIG_IGN);
235 }
236 sigmode[signo - 1] = S_HARD_IGN;
237 }
238
239
240 #ifdef mkinit
241 INCLUDE "signames.h"
242 INCLUDE "trap.h"
243
244 SHELLPROC {
245 char *sm;
246
247 clear_traps();
248 for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) {
249 if (*sm == S_IGN)
250 *sm = S_HARD_IGN;
251 }
252 }
253 #endif
254
255
256
257 /*
258 * Signal handler.
259 */
260
261 void
262 onsig(signo) {
263 signal(signo, onsig);
264 if (signo == SIGINT && trap[SIGINT] == NULL) {
265 onint();
266 return;
267 }
268 gotsig[signo - 1] = 1;
269 pendingsigs++;
270 }
271
272
273
274 /*
275 * Called to execute a trap. Perhaps we should avoid entering new trap
276 * handlers while we are executing a trap handler.
277 */
278
279 void
280 dotrap() {
281 int i;
282 int savestatus;
283
284 for (;;) {
285 for (i = 1 ; ; i++) {
286 if (gotsig[i - 1])
287 break;
288 if (i >= MAXSIG)
289 goto done;
290 }
291 gotsig[i - 1] = 0;
292 savestatus=exitstatus;
293 evalstring(trap[i]);
294 exitstatus=savestatus;
295 }
296 done:
297 pendingsigs = 0;
298 }
299
300
301
302 /*
303 * Controls whether the shell is interactive or not.
304 */
305
306
307 void
308 setinteractive(on) {
309 static int is_interactive;
310
311 if (on == is_interactive)
312 return;
313 setsignal(SIGINT);
314 setsignal(SIGQUIT);
315 setsignal(SIGTERM);
316 is_interactive = on;
317 }
318
319
320
321 /*
322 * Called to exit the shell.
323 */
324
325 void
326 exitshell(status) {
327 struct jmploc loc1, loc2;
328 char *p;
329
330 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
331 if (setjmp(loc1.loc)) {
332 goto l1;
333 }
334 if (setjmp(loc2.loc)) {
335 goto l2;
336 }
337 handler = &loc1;
338 if ((p = trap[0]) != NULL && *p != '\0') {
339 trap[0] = NULL;
340 evalstring(p);
341 }
342 l1: handler = &loc2; /* probably unnecessary */
343 flushall();
344 #if JOBS
345 setjobctl(0);
346 #endif
347 l2: _exit(status);
348 }
349