trap.c revision 1.3 1 /*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * 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 5.2 (Berkeley) 4/12/91";
39 static char rcsid[] = "$Header: /tank/opengrok/rsync2/NetBSD/src/bin/sh/trap.c,v 1.3 1993/03/23 00:29:28 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 "signames.h"
50 #include "output.h"
51 #include "memalloc.h"
52 #include "error.h"
53 #include "trap.h"
54 #include "mystring.h"
55 #include <signal.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
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
151 if ((t = trap[signo]) == NULL)
152 action = S_DFL;
153 else if (*t != '\0')
154 action = S_CATCH;
155 else
156 action = S_IGN;
157 if (rootshell && action == S_DFL) {
158 switch (signo) {
159 case SIGINT:
160 if (iflag)
161 action = S_CATCH;
162 break;
163 case SIGQUIT:
164 #ifdef DEBUG
165 {
166 extern int debug;
167
168 if (debug)
169 break;
170 }
171 #endif
172 /* FALLTHROUGH */
173 case SIGTERM:
174 if (iflag)
175 action = S_IGN;
176 break;
177 #if JOBS
178 case SIGTSTP:
179 case SIGTTOU:
180 if (jflag)
181 action = S_IGN;
182 break;
183 #endif
184 }
185 }
186 t = &sigmode[signo - 1];
187 if (*t == 0) { /* current setting unknown */
188 /*
189 * There is a race condition here if action is not S_IGN.
190 * A signal can be ignored that shouldn't be.
191 */
192 if ((int)(sigact = signal(signo, SIG_IGN)) == -1)
193 error("Signal system call failed");
194 if (sigact == SIG_IGN) {
195 *t = S_HARD_IGN;
196 } else {
197 *t = S_IGN;
198 }
199 }
200 if (*t == S_HARD_IGN || *t == action)
201 return 0;
202 switch (action) {
203 case S_DFL: sigact = SIG_DFL; break;
204 case S_CATCH: sigact = onsig; break;
205 case S_IGN: sigact = SIG_IGN; break;
206 }
207 *t = action;
208 return (int)signal(signo, sigact);
209 }
210
211
212 /*
213 * Ignore a signal.
214 */
215
216 void
217 ignoresig(signo) {
218 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
219 signal(signo, SIG_IGN);
220 }
221 sigmode[signo - 1] = S_HARD_IGN;
222 }
223
224
225 #ifdef mkinit
226 INCLUDE "signames.h"
227 INCLUDE "trap.h"
228
229 SHELLPROC {
230 char *sm;
231
232 clear_traps();
233 for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) {
234 if (*sm == S_IGN)
235 *sm = S_HARD_IGN;
236 }
237 }
238 #endif
239
240
241
242 /*
243 * Signal handler.
244 */
245
246 void
247 onsig(signo) {
248 signal(signo, onsig);
249 if (signo == SIGINT && trap[SIGINT] == NULL) {
250 onint();
251 return;
252 }
253 gotsig[signo - 1] = 1;
254 pendingsigs++;
255 }
256
257
258
259 /*
260 * Called to execute a trap. Perhaps we should avoid entering new trap
261 * handlers while we are executing a trap handler.
262 */
263
264 void
265 dotrap() {
266 int i;
267 int savestatus;
268
269 for (;;) {
270 for (i = 1 ; ; i++) {
271 if (gotsig[i - 1])
272 break;
273 if (i >= MAXSIG)
274 goto done;
275 }
276 gotsig[i - 1] = 0;
277 savestatus=exitstatus;
278 evalstring(trap[i]);
279 exitstatus=savestatus;
280 }
281 done:
282 pendingsigs = 0;
283 }
284
285
286
287 /*
288 * Controls whether the shell is interactive or not.
289 */
290
291 int is_interactive;
292
293 void
294 setinteractive(on) {
295 if (on == is_interactive)
296 return;
297 setsignal(SIGINT);
298 setsignal(SIGQUIT);
299 setsignal(SIGTERM);
300 is_interactive = on;
301 }
302
303
304
305 /*
306 * Called to exit the shell.
307 */
308
309 void
310 exitshell(status) {
311 struct jmploc loc1, loc2;
312 char *p;
313
314 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
315 if (setjmp(loc1.loc)) goto l1;
316 if (setjmp(loc2.loc)) goto l2;
317 handler = &loc1;
318 if ((p = trap[0]) != NULL && *p != '\0') {
319 trap[0] = NULL;
320 evalstring(p);
321 }
322 l1: handler = &loc2; /* probably unnecessary */
323 flushall();
324 #if JOBS
325 setjobctl(0);
326 #endif
327 l2: _exit(status);
328 }
329