trap.c revision 194127
1159307Spjd/*-
2220922Spjd * Copyright (c) 1991, 1993
3159307Spjd *	The Regents of the University of California.  All rights reserved.
4159307Spjd *
5159307Spjd * This code is derived from software contributed to Berkeley by
6159307Spjd * Kenneth Almquist.
7159307Spjd *
8159307Spjd * Redistribution and use in source and binary forms, with or without
9159307Spjd * modification, are permitted provided that the following conditions
10159307Spjd * are met:
11159307Spjd * 1. Redistributions of source code must retain the above copyright
12159307Spjd *    notice, this list of conditions and the following disclaimer.
13159307Spjd * 2. Redistributions in binary form must reproduce the above copyright
14159307Spjd *    notice, this list of conditions and the following disclaimer in the
15159307Spjd *    documentation and/or other materials provided with the distribution.
16159307Spjd * 4. Neither the name of the University nor the names of its contributors
17159307Spjd *    may be used to endorse or promote products derived from this software
18159307Spjd *    without specific prior written permission.
19159307Spjd *
20159307Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21159307Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22159307Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23159307Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24159307Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25159307Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26159307Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27159307Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28159307Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29159307Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30159307Spjd * SUCH DAMAGE.
31159307Spjd */
32159307Spjd
33159307Spjd#ifndef lint
34159307Spjd#if 0
35159307Spjdstatic char sccsid[] = "@(#)trap.c	8.5 (Berkeley) 6/5/95";
36159307Spjd#endif
37159307Spjd#endif /* not lint */
38159307Spjd#include <sys/cdefs.h>
39159307Spjd__FBSDID("$FreeBSD: head/bin/sh/trap.c 194127 2009-06-13 21:10:41Z jilles $");
40159307Spjd
41159307Spjd#include <signal.h>
42159307Spjd#include <unistd.h>
43159307Spjd#include <stdlib.h>
44159307Spjd
45159307Spjd#include "shell.h"
46159307Spjd#include "main.h"
47159307Spjd#include "nodes.h"	/* for other headers */
48159307Spjd#include "eval.h"
49159307Spjd#include "jobs.h"
50159307Spjd#include "show.h"
51159307Spjd#include "options.h"
52159307Spjd#include "syntax.h"
53159307Spjd#include "output.h"
54159307Spjd#include "memalloc.h"
55159307Spjd#include "error.h"
56159307Spjd#include "trap.h"
57159307Spjd#include "mystring.h"
58159307Spjd#include "myhistedit.h"
59159307Spjd
60159307Spjd
61159307Spjd/*
62159307Spjd * Sigmode records the current value of the signal handlers for the various
63159307Spjd * modes.  A value of zero means that the current handler is not known.
64159307Spjd * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
65159307Spjd */
66159307Spjd
67159307Spjd#define S_DFL 1			/* default signal handling (SIG_DFL) */
68159307Spjd#define S_CATCH 2		/* signal is caught */
69159307Spjd#define S_IGN 3			/* signal is ignored (SIG_IGN) */
70159307Spjd#define S_HARD_IGN 4		/* signal is ignored permanently */
71159307Spjd#define S_RESET 5		/* temporary - to reset a hard ignored sig */
72159307Spjd
73159307Spjd
74159307SpjdMKINIT char sigmode[NSIG];	/* current value of signal */
75159307Spjdint pendingsigs;		/* indicates some signal received */
76159307Spjdint in_dotrap;			/* do we execute in a trap handler? */
77159307Spjdstatic char *volatile trap[NSIG];	/* trap handler commands */
78159307Spjdstatic volatile sig_atomic_t gotsig[NSIG];
79159307Spjd				/* indicates specified signal received */
80159307Spjdstatic int ignore_sigchld;	/* Used while handling SIGCHLD traps. */
81159307Spjdvolatile sig_atomic_t gotwinch;
82159307Spjd
83159307Spjdstatic int getsigaction(int, sig_t *);
84159307Spjd
85159307Spjd
86159307Spjd/*
87159307Spjd * Map a string to a signal number.
88159307Spjd *
89159307Spjd * Note: the signal number may exceed NSIG.
90159307Spjd */
91159307Spjdstatic int
92159307Spjdsigstring_to_signum(char *sig)
93159307Spjd{
94159307Spjd
95159307Spjd	if (is_number(sig)) {
96159307Spjd		int signo;
97159307Spjd
98159307Spjd		signo = atoi(sig);
99159307Spjd		return ((signo >= 0 && signo < NSIG) ? signo : (-1));
100159307Spjd	} else if (strcasecmp(sig, "exit") == 0) {
101159307Spjd		return (0);
102159307Spjd	} else {
103159307Spjd		int n;
104159307Spjd
105159307Spjd		if (strncasecmp(sig, "sig", 3) == 0)
106159307Spjd			sig += 3;
107159307Spjd		for (n = 1; n < sys_nsig; n++)
108159307Spjd			if (sys_signame[n] &&
109159307Spjd			    strcasecmp(sys_signame[n], sig) == 0)
110159307Spjd				return (n);
111159307Spjd	}
112159307Spjd	return (-1);
113159307Spjd}
114159307Spjd
115159307Spjd
116159307Spjd/*
117159307Spjd * Print a list of valid signal names.
118159307Spjd */
119159307Spjdstatic void
120159307Spjdprintsignals(void)
121159307Spjd{
122159307Spjd	int n, outlen;
123159307Spjd
124159307Spjd	outlen = 0;
125159307Spjd	for (n = 1; n < sys_nsig; n++) {
126159307Spjd		if (sys_signame[n]) {
127159307Spjd			out1fmt("%s", sys_signame[n]);
128159307Spjd			outlen += strlen(sys_signame[n]);
129159307Spjd		} else {
130159307Spjd			out1fmt("%d", n);
131159307Spjd			outlen += 3;	/* good enough */
132214118Spjd		}
133159307Spjd		++outlen;
134159307Spjd		if (outlen > 70 || n == sys_nsig - 1) {
135159307Spjd			out1str("\n");
136159307Spjd			outlen = 0;
137159307Spjd		} else {
138159307Spjd			out1c(' ');
139159307Spjd		}
140159307Spjd	}
141159307Spjd}
142159307Spjd
143159307Spjd
144159307Spjd/*
145159307Spjd * The trap builtin.
146159307Spjd */
147159307Spjdint
148159307Spjdtrapcmd(int argc, char **argv)
149159307Spjd{
150159307Spjd	char *action;
151220922Spjd	int signo;
152221625Spjd
153159307Spjd	if (argc <= 1) {
154159307Spjd		for (signo = 0 ; signo < sys_nsig ; signo++) {
155159307Spjd			if (signo < NSIG && trap[signo] != NULL) {
156159307Spjd				out1str("trap -- ");
157159307Spjd				out1qstr(trap[signo]);
158159307Spjd				if (signo == 0) {
159159307Spjd					out1str(" exit\n");
160159307Spjd				} else if (sys_signame[signo]) {
161159307Spjd					out1fmt(" %s\n", sys_signame[signo]);
162159307Spjd				} else {
163159307Spjd					out1fmt(" %d\n", signo);
164159307Spjd				}
165159307Spjd			}
166159307Spjd		}
167159307Spjd		return 0;
168159307Spjd	}
169159307Spjd	action = NULL;
170159307Spjd	if (*++argv && strcmp(*argv, "--") == 0)
171159307Spjd		argv++;
172159307Spjd	if (*argv && sigstring_to_signum(*argv) == -1) {
173159307Spjd		if ((*argv)[0] != '-') {
174159307Spjd			action = *argv;
175159307Spjd			argv++;
176159307Spjd		} else if ((*argv)[1] == '\0') {
177159307Spjd			argv++;
178159307Spjd		} else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
179159307Spjd			printsignals();
180159307Spjd			return 0;
181159307Spjd		} else {
182159307Spjd			error("bad option %s", *argv);
183159307Spjd		}
184159307Spjd	}
185159307Spjd	while (*argv) {
186159307Spjd		if ((signo = sigstring_to_signum(*argv)) == -1)
187159307Spjd			error("bad signal %s", *argv);
188159307Spjd		INTOFF;
189159307Spjd		if (action)
190159307Spjd			action = savestr(action);
191159307Spjd		if (trap[signo])
192159307Spjd			ckfree(trap[signo]);
193159307Spjd		trap[signo] = action;
194159307Spjd		if (signo != 0)
195159307Spjd			setsignal(signo);
196159307Spjd		INTON;
197159307Spjd		argv++;
198159307Spjd	}
199159307Spjd	return 0;
200159307Spjd}
201159307Spjd
202159307Spjd
203159307Spjd/*
204159307Spjd * Clear traps on a fork.
205159307Spjd */
206159307Spjdvoid
207159307Spjdclear_traps(void)
208235201Seadler{
209235419Seadler	char *volatile *tp;
210159307Spjd
211159307Spjd	for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) {
212159307Spjd		if (*tp && **tp) {	/* trap not NULL or SIG_IGN */
213159307Spjd			INTOFF;
214159307Spjd			ckfree(*tp);
215159307Spjd			*tp = NULL;
216159307Spjd			if (tp != &trap[0])
217159307Spjd				setsignal(tp - trap);
218159307Spjd			INTON;
219159307Spjd		}
220159307Spjd	}
221159307Spjd}
222159307Spjd
223159307Spjd
224235201Seadler/*
225235419Seadler * Check if we have any traps enabled.
226159307Spjd */
227159307Spjdint
228159307Spjdhave_traps(void)
229159307Spjd{
230159307Spjd	char *volatile *tp;
231159307Spjd
232159307Spjd	for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) {
233159307Spjd		if (*tp && **tp)	/* trap not NULL or SIG_IGN */
234159307Spjd			return 1;
235159307Spjd	}
236159307Spjd	return 0;
237159307Spjd}
238159307Spjd
239159307Spjd/*
240159307Spjd * Set the signal handler for the specified signal.  The routine figures
241159307Spjd * out what it should be set to.
242159307Spjd */
243159307Spjdvoid
244159307Spjdsetsignal(int signo)
245214118Spjd{
246159307Spjd	int action;
247159307Spjd	sig_t sig, sigact = SIG_DFL;
248159307Spjd	char *t;
249159307Spjd
250159307Spjd	if ((t = trap[signo]) == NULL)
251159307Spjd		action = S_DFL;
252159307Spjd	else if (*t != '\0')
253159307Spjd		action = S_CATCH;
254159307Spjd	else
255159307Spjd		action = S_IGN;
256159307Spjd	if (action == S_DFL) {
257159307Spjd		switch (signo) {
258159307Spjd		case SIGINT:
259159307Spjd			action = S_CATCH;
260159307Spjd			break;
261159307Spjd		case SIGQUIT:
262159307Spjd#ifdef DEBUG
263159307Spjd			{
264159307Spjd			extern int debug;
265159307Spjd
266159307Spjd			if (debug)
267159307Spjd				break;
268159307Spjd			}
269159307Spjd#endif
270159307Spjd			action = S_CATCH;
271159307Spjd			break;
272159307Spjd		case SIGTERM:
273159307Spjd			if (rootshell && iflag)
274159307Spjd				action = S_IGN;
275159307Spjd			break;
276159307Spjd#if JOBS
277220922Spjd		case SIGTSTP:
278220922Spjd		case SIGTTOU:
279159307Spjd			if (rootshell && mflag)
280159307Spjd				action = S_IGN;
281159307Spjd			break;
282159307Spjd#endif
283159307Spjd#ifndef NO_HISTORY
284159307Spjd		case SIGWINCH:
285159307Spjd			if (rootshell && iflag)
286159307Spjd				action = S_CATCH;
287159307Spjd			break;
288159307Spjd#endif
289159307Spjd		}
290159307Spjd	}
291159307Spjd
292159307Spjd	t = &sigmode[signo];
293214118Spjd	if (*t == 0) {
294159307Spjd		/*
295159307Spjd		 * current setting unknown
296159307Spjd		 */
297159307Spjd		if (!getsigaction(signo, &sigact)) {
298159307Spjd			/*
299159307Spjd			 * Pretend it worked; maybe we should give a warning
300159307Spjd			 * here, but other shells don't. We don't alter
301159307Spjd			 * sigmode, so that we retry every time.
302159307Spjd			 */
303159307Spjd			return;
304159307Spjd		}
305159307Spjd		if (sigact == SIG_IGN) {
306159307Spjd			if (mflag && (signo == SIGTSTP ||
307159307Spjd			     signo == SIGTTIN || signo == SIGTTOU)) {
308159307Spjd				*t = S_IGN;	/* don't hard ignore these */
309159307Spjd			} else
310159307Spjd				*t = S_HARD_IGN;
311159307Spjd		} else {
312159307Spjd			*t = S_RESET;	/* force to be set */
313159307Spjd		}
314159307Spjd	}
315159307Spjd	if (*t == S_HARD_IGN || *t == action)
316159307Spjd		return;
317159307Spjd	switch (action) {
318159307Spjd		case S_DFL:	sigact = SIG_DFL;	break;
319159307Spjd		case S_CATCH:  	sigact = onsig;		break;
320159307Spjd		case S_IGN:	sigact = SIG_IGN;	break;
321159307Spjd	}
322159307Spjd	*t = action;
323159307Spjd	sig = signal(signo, sigact);
324159307Spjd	if (sig != SIG_ERR && action == S_CATCH)
325159307Spjd		siginterrupt(signo, 1);
326159307Spjd}
327159307Spjd
328159307Spjd
329159307Spjd/*
330159307Spjd * Return the current setting for sig w/o changing it.
331159307Spjd */
332159307Spjdstatic int
333159307Spjdgetsigaction(int signo, sig_t *sigact)
334159307Spjd{
335159307Spjd	struct sigaction sa;
336159307Spjd
337159307Spjd	if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
338159307Spjd		return 0;
339159307Spjd	*sigact = (sig_t) sa.sa_handler;
340159307Spjd	return 1;
341159307Spjd}
342159307Spjd
343159307Spjd
344159307Spjd/*
345159307Spjd * Ignore a signal.
346159307Spjd */
347159307Spjdvoid
348159307Spjdignoresig(int signo)
349159307Spjd{
350159307Spjd
351159307Spjd	if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
352159307Spjd		signal(signo, SIG_IGN);
353159307Spjd	}
354159307Spjd	sigmode[signo] = S_HARD_IGN;
355159307Spjd}
356159307Spjd
357159307Spjd
358159307Spjd#ifdef mkinit
359159307SpjdINCLUDE <signal.h>
360159307SpjdINCLUDE "trap.h"
361159307Spjd
362159307SpjdSHELLPROC {
363159307Spjd	char *sm;
364159307Spjd
365159307Spjd	clear_traps();
366159307Spjd	for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
367159307Spjd		if (*sm == S_IGN)
368159307Spjd			*sm = S_HARD_IGN;
369159307Spjd	}
370159307Spjd}
371159307Spjd#endif
372159307Spjd
373159307Spjd
374159307Spjd/*
375159307Spjd * Signal handler.
376159307Spjd */
377159307Spjdvoid
378159307Spjdonsig(int signo)
379159307Spjd{
380159307Spjd
381159307Spjd	if (signo == SIGINT && trap[SIGINT] == NULL) {
382159307Spjd		onint();
383159307Spjd		return;
384159307Spjd	}
385159307Spjd
386159307Spjd	if (signo != SIGCHLD || !ignore_sigchld)
387159307Spjd		gotsig[signo] = 1;
388159307Spjd	pendingsigs++;
389159307Spjd
390159307Spjd	/* If we are currently in a wait builtin, prepare to break it */
391159307Spjd	if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0)
392159307Spjd		breakwaitcmd = 1;
393159307Spjd	/*
394159307Spjd	 * If a trap is set, not ignored and not the null command, we need
395159307Spjd	 * to make sure traps are executed even when a child blocks signals.
396159307Spjd	 */
397159307Spjd	if (Tflag &&
398159307Spjd	    trap[signo] != NULL &&
399159307Spjd	    ! (trap[signo][0] == '\0') &&
400214116Spjd	    ! (trap[signo][0] == ':' && trap[signo][1] == '\0'))
401214116Spjd		breakwaitcmd = 1;
402214116Spjd
403214116Spjd#ifndef NO_HISTORY
404214116Spjd	if (signo == SIGWINCH)
405159307Spjd		gotwinch = 1;
406159307Spjd#endif
407159307Spjd}
408159307Spjd
409159307Spjd
410159307Spjd/*
411159307Spjd * Called to execute a trap.  Perhaps we should avoid entering new trap
412159307Spjd * handlers while we are executing a trap handler.
413159307Spjd */
414159307Spjdvoid
415159307Spjddotrap(void)
416159307Spjd{
417159307Spjd	int i;
418159307Spjd	int savestatus;
419159307Spjd
420159307Spjd	in_dotrap++;
421159307Spjd	for (;;) {
422159307Spjd		for (i = 1; i < NSIG; i++) {
423159307Spjd			if (gotsig[i]) {
424159307Spjd				gotsig[i] = 0;
425159307Spjd				if (trap[i]) {
426159307Spjd					/*
427159307Spjd					 * Ignore SIGCHLD to avoid infinite
428159307Spjd					 * recursion if the trap action does
429159307Spjd					 * a fork.
430159307Spjd					 */
431159307Spjd					if (i == SIGCHLD)
432159307Spjd						ignore_sigchld++;
433159307Spjd					savestatus = exitstatus;
434159307Spjd					evalstring(trap[i], 0);
435159307Spjd					exitstatus = savestatus;
436159307Spjd					if (i == SIGCHLD)
437159307Spjd						ignore_sigchld--;
438159343Spjd				}
439159307Spjd				break;
440159307Spjd			}
441159307Spjd		}
442159307Spjd		if (i >= NSIG)
443159307Spjd			break;
444159307Spjd	}
445159307Spjd	in_dotrap--;
446159307Spjd	pendingsigs = 0;
447159307Spjd}
448159307Spjd
449159307Spjd
450159307Spjd/*
451159307Spjd * Controls whether the shell is interactive or not.
452159307Spjd */
453159307Spjdvoid
454159307Spjdsetinteractive(int on)
455159307Spjd{
456159307Spjd	static int is_interactive = -1;
457159307Spjd
458159307Spjd	if (on == is_interactive)
459159307Spjd		return;
460159307Spjd	setsignal(SIGINT);
461159307Spjd	setsignal(SIGQUIT);
462159307Spjd	setsignal(SIGTERM);
463159307Spjd#ifndef NO_HISTORY
464159307Spjd	setsignal(SIGWINCH);
465159307Spjd#endif
466159307Spjd	is_interactive = on;
467159307Spjd}
468159307Spjd
469159307Spjd
470159307Spjd/*
471159307Spjd * Called to exit the shell.
472159307Spjd */
473159307Spjdvoid
474159307Spjdexitshell(int status)
475159307Spjd{
476159307Spjd	struct jmploc loc1, loc2;
477159307Spjd	char *p;
478159307Spjd
479159307Spjd	TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
480159307Spjd	if (setjmp(loc1.loc)) {
481159307Spjd		goto l1;
482159307Spjd	}
483159307Spjd	if (setjmp(loc2.loc)) {
484159307Spjd		goto l2;
485159307Spjd	}
486159307Spjd	handler = &loc1;
487159307Spjd	if ((p = trap[0]) != NULL && *p != '\0') {
488159307Spjd		trap[0] = NULL;
489159307Spjd		evalstring(p, 0);
490159307Spjd	}
491159307Spjdl1:   handler = &loc2;			/* probably unnecessary */
492159307Spjd	flushall();
493159307Spjd#if JOBS
494159307Spjd	setjobctl(0);
495159343Spjd#endif
496160569Spjdl2:   _exit(status);
497159307Spjd}
498159307Spjd