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