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