trap.c revision 1556
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
38static 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
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#define S_RESET 5		/* temporary - to reset a hard ignored sig */
68
69
70extern char nullstr[1];		/* null string */
71
72char *trap[MAXSIG+1];		/* trap handler commands */
73MKINIT char sigmode[MAXSIG];	/* current value of signal */
74char gotsig[MAXSIG];		/* indicates specified signal received */
75int pendingsigs;			/* indicates some signal received */
76
77/*
78 * The trap builtin.
79 */
80
81trapcmd(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
121void
122clear_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
144int
145setsignal(signo) {
146	int action;
147	sig_t sigact;
148	char *t;
149	extern void onsig();
150	extern sig_t getsigaction();
151
152	if ((t = trap[signo]) == NULL)
153		action = S_DFL;
154	else if (*t != '\0')
155		action = S_CATCH;
156	else
157		action = S_IGN;
158	if (rootshell && action == S_DFL) {
159		switch (signo) {
160		case SIGINT:
161			if (iflag)
162				action = S_CATCH;
163			break;
164		case SIGQUIT:
165#ifdef DEBUG
166			{
167			extern int debug;
168
169			if (debug)
170				break;
171			}
172#endif
173			/* FALLTHROUGH */
174		case SIGTERM:
175			if (iflag)
176				action = S_IGN;
177			break;
178#if JOBS
179		case SIGTSTP:
180		case SIGTTOU:
181			if (mflag)
182				action = S_IGN;
183			break;
184#endif
185		}
186	}
187	t = &sigmode[signo - 1];
188	if (*t == 0) {
189		/*
190		 * current setting unknown
191		 */
192		sigact = getsigaction(signo);
193		if (sigact == SIG_IGN) {
194			if (mflag && (signo == SIGTSTP ||
195			     signo == SIGTTIN || signo == SIGTTOU)) {
196				*t = S_IGN;	/* don't hard ignore these */
197			} else
198				*t = S_HARD_IGN;
199		} else {
200			*t = S_RESET;	/* force to be set */
201		}
202	}
203	if (*t == S_HARD_IGN || *t == action)
204		return 0;
205	switch (action) {
206		case S_DFL:	sigact = SIG_DFL;	break;
207		case S_CATCH:  	sigact = onsig;		break;
208		case S_IGN:	sigact = SIG_IGN;	break;
209	}
210	*t = action;
211	return (int)signal(signo, sigact);
212}
213
214/*
215 * Return the current setting for sig w/o changing it.
216 */
217sig_t
218getsigaction(signo) {
219	struct sigaction sa;
220
221	if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
222		error("Sigaction system call failed");
223
224	return sa.sa_handler;
225}
226
227/*
228 * Ignore a signal.
229 */
230
231void
232ignoresig(signo) {
233	if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
234		signal(signo, SIG_IGN);
235	}
236	sigmode[signo - 1] = S_HARD_IGN;
237}
238
239
240#ifdef mkinit
241INCLUDE "signames.h"
242INCLUDE "trap.h"
243
244SHELLPROC {
245	char *sm;
246
247	clear_traps();
248	for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) {
249		if (*sm == S_IGN)
250			*sm = S_HARD_IGN;
251	}
252}
253#endif
254
255
256
257/*
258 * Signal handler.
259 */
260
261void
262onsig(signo) {
263	signal(signo, onsig);
264	if (signo == SIGINT && trap[SIGINT] == NULL) {
265		onint();
266		return;
267	}
268	gotsig[signo - 1] = 1;
269	pendingsigs++;
270}
271
272
273
274/*
275 * Called to execute a trap.  Perhaps we should avoid entering new trap
276 * handlers while we are executing a trap handler.
277 */
278
279void
280dotrap() {
281	int i;
282	int savestatus;
283
284	for (;;) {
285		for (i = 1 ; ; i++) {
286			if (gotsig[i - 1])
287				break;
288			if (i >= MAXSIG)
289				goto done;
290		}
291		gotsig[i - 1] = 0;
292		savestatus=exitstatus;
293		evalstring(trap[i]);
294		exitstatus=savestatus;
295	}
296done:
297	pendingsigs = 0;
298}
299
300
301
302/*
303 * Controls whether the shell is interactive or not.
304 */
305
306
307void
308setinteractive(on) {
309	static int is_interactive;
310
311	if (on == is_interactive)
312		return;
313	setsignal(SIGINT);
314	setsignal(SIGQUIT);
315	setsignal(SIGTERM);
316	is_interactive = on;
317}
318
319
320
321/*
322 * Called to exit the shell.
323 */
324
325void
326exitshell(status) {
327	struct jmploc loc1, loc2;
328	char *p;
329
330	TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
331	if (setjmp(loc1.loc)) {
332		goto l1;
333	}
334	if (setjmp(loc2.loc)) {
335		goto l2;
336	}
337	handler = &loc1;
338	if ((p = trap[0]) != NULL && *p != '\0') {
339		trap[0] = NULL;
340		evalstring(p);
341	}
342l1:   handler = &loc2;			/* probably unnecessary */
343	flushall();
344#if JOBS
345	setjobctl(0);
346#endif
347l2:   _exit(status);
348}
349