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