Just talked with James - there's another, better way to go about this.
[unix-history] / bin / sh / trap.c
CommitLineData
15637ed4
RG
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
68de1ca3
AM
38/*static char sccsid[] = "from: @(#)trap.c 5.2 (Berkeley) 4/12/91";*/
39static char rcsid[] = "trap.c,v 1.5 1993/08/06 21:50:18 mycroft Exp";
15637ed4
RG
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"
15637ed4
RG
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
56
57/*
58 * Sigmode records the current value of the signal handlers for the various
59 * modes. A value of zero means that the current handler is not known.
60 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
61 */
62
63#define S_DFL 1 /* default signal handling (SIG_DFL) */
64#define S_CATCH 2 /* signal is caught */
65#define S_IGN 3 /* signal is ignored (SIG_IGN) */
66#define S_HARD_IGN 4 /* signal is ignored permenantly */
67
68
69extern char nullstr[1]; /* null string */
70
68de1ca3
AM
71char *trap[NSIG]; /* trap handler commands */
72MKINIT char sigmode[NSIG]; /* current value of signal */
73char gotsig[NSIG]; /* indicates specified signal received */
74int pendingsigs; /* indicates some signal received */
15637ed4
RG
75
76/*
77 * The trap builtin.
78 */
79
80trapcmd(argc, argv) char **argv; {
81 char *action;
82 char **ap;
83 int signo;
84
85 if (argc <= 1) {
68de1ca3 86 for (signo = 0 ; signo < NSIG ; signo++) {
15637ed4
RG
87 if (trap[signo] != NULL)
88 out1fmt("%d: %s\n", signo, trap[signo]);
89 }
90 return 0;
91 }
92 ap = argv + 1;
93 if (is_number(*ap))
94 action = NULL;
95 else
96 action = *ap++;
97 while (*ap) {
68de1ca3 98 if ((signo = number(*ap)) < 0 || signo >= NSIG)
15637ed4
RG
99 error("%s: bad trap", *ap);
100 INTOFF;
101 if (action)
102 action = savestr(action);
103 if (trap[signo])
104 ckfree(trap[signo]);
105 trap[signo] = action;
106 if (signo != 0)
107 setsignal(signo);
108 INTON;
109 ap++;
110 }
111 return 0;
112}
113
114
115
116/*
117 * Clear traps on a fork.
118 */
119
120void
121clear_traps() {
122 char **tp;
123
68de1ca3 124 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
15637ed4
RG
125 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
126 INTOFF;
127 ckfree(*tp);
128 *tp = NULL;
129 if (tp != &trap[0])
130 setsignal(tp - trap);
131 INTON;
132 }
133 }
134}
135
136
137
138/*
139 * Set the signal handler for the specified signal. The routine figures
140 * out what it should be set to.
141 */
142
143int
144setsignal(signo) {
145 int action;
146 sig_t sigact;
147 char *t;
148 extern void onsig();
149
150 if ((t = trap[signo]) == NULL)
151 action = S_DFL;
152 else if (*t != '\0')
153 action = S_CATCH;
154 else
155 action = S_IGN;
156 if (rootshell && action == S_DFL) {
157 switch (signo) {
158 case SIGINT:
159 if (iflag)
160 action = S_CATCH;
161 break;
162 case SIGQUIT:
163#ifdef DEBUG
164 {
165 extern int debug;
166
167 if (debug)
168 break;
169 }
170#endif
171 /* FALLTHROUGH */
172 case SIGTERM:
173 if (iflag)
174 action = S_IGN;
175 break;
176#if JOBS
177 case SIGTSTP:
178 case SIGTTOU:
179 if (jflag)
180 action = S_IGN;
181 break;
182#endif
183 }
184 }
68de1ca3 185 t = &sigmode[signo];
15637ed4
RG
186 if (*t == 0) { /* current setting unknown */
187 /*
188 * There is a race condition here if action is not S_IGN.
189 * A signal can be ignored that shouldn't be.
190 */
191 if ((int)(sigact = signal(signo, SIG_IGN)) == -1)
192 error("Signal system call failed");
193 if (sigact == SIG_IGN) {
194 *t = S_HARD_IGN;
195 } else {
196 *t = S_IGN;
197 }
198 }
199 if (*t == S_HARD_IGN || *t == action)
200 return 0;
201 switch (action) {
202 case S_DFL: sigact = SIG_DFL; break;
203 case S_CATCH: sigact = onsig; break;
204 case S_IGN: sigact = SIG_IGN; break;
205 }
206 *t = action;
207 return (int)signal(signo, sigact);
208}
209
210
211/*
212 * Ignore a signal.
213 */
214
215void
216ignoresig(signo) {
68de1ca3 217 if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
15637ed4
RG
218 signal(signo, SIG_IGN);
219 }
68de1ca3 220 sigmode[signo] = S_HARD_IGN;
15637ed4
RG
221}
222
223
224#ifdef mkinit
68de1ca3 225INCLUDE <sys/signal.h>
15637ed4
RG
226INCLUDE "trap.h"
227
228SHELLPROC {
229 char *sm;
230
231 clear_traps();
68de1ca3 232 for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
15637ed4
RG
233 if (*sm == S_IGN)
234 *sm = S_HARD_IGN;
235 }
236}
237#endif
238
239
240
241/*
242 * Signal handler.
243 */
244
245void
246onsig(signo) {
247 signal(signo, onsig);
248 if (signo == SIGINT && trap[SIGINT] == NULL) {
249 onint();
250 return;
251 }
68de1ca3 252 gotsig[signo] = 1;
15637ed4
RG
253 pendingsigs++;
254}
255
256
257
258/*
259 * Called to execute a trap. Perhaps we should avoid entering new trap
260 * handlers while we are executing a trap handler.
261 */
262
263void
264dotrap() {
265 int i;
266 int savestatus;
267
268 for (;;) {
269 for (i = 1 ; ; i++) {
68de1ca3 270 if (i >= NSIG)
15637ed4 271 goto done;
68de1ca3
AM
272 if (gotsig[i])
273 break;
15637ed4 274 }
68de1ca3 275 gotsig[i] = 0;
15637ed4
RG
276 savestatus=exitstatus;
277 evalstring(trap[i]);
278 exitstatus=savestatus;
279 }
280done:
281 pendingsigs = 0;
282}
283
284
285
286/*
287 * Controls whether the shell is interactive or not.
288 */
289
290int is_interactive;
291
292void
293setinteractive(on) {
294 if (on == is_interactive)
295 return;
296 setsignal(SIGINT);
297 setsignal(SIGQUIT);
298 setsignal(SIGTERM);
299 is_interactive = on;
300}
301
302
303
304/*
305 * Called to exit the shell.
306 */
307
308void
309exitshell(status) {
310 struct jmploc loc1, loc2;
311 char *p;
312
313 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
314 if (setjmp(loc1.loc)) goto l1;
315 if (setjmp(loc2.loc)) goto l2;
316 handler = &loc1;
317 if ((p = trap[0]) != NULL && *p != '\0') {
318 trap[0] = NULL;
319 evalstring(p);
320 }
321l1: handler = &loc2; /* probably unnecessary */
322 flushall();
323#if JOBS
324 setjobctl(0);
325#endif
326l2: _exit(status);
327}