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