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