trap.c revision 157811
1132744Skan/*-
290285Sobrien * Copyright (c) 1991, 1993
3169706Skan *	The Regents of the University of California.  All rights reserved.
418334Speter *
5132744Skan * This code is derived from software contributed to Berkeley by
618334Speter * Kenneth Almquist.
7132744Skan *
818334Speter * Redistribution and use in source and binary forms, with or without
918334Speter * modification, are permitted provided that the following conditions
1018334Speter * are met:
1118334Speter * 1. Redistributions of source code must retain the above copyright
12132744Skan *    notice, this list of conditions and the following disclaimer.
1318334Speter * 2. Redistributions in binary form must reproduce the above copyright
1418334Speter *    notice, this list of conditions and the following disclaimer in the
1518334Speter *    documentation and/or other materials provided with the distribution.
1618334Speter * 4. Neither the name of the University nor the names of its contributors
1718334Speter *    may be used to endorse or promote products derived from this software
18132744Skan *    without specific prior written permission.
19169706Skan *
20169706Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2118334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2218334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2318334Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2418334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2518334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2618334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2718334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2818334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2918334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3018334Speter * SUCH DAMAGE.
3118334Speter */
3218334Speter
3390285Sobrien#ifndef lint
3490285Sobrien#if 0
3590285Sobrienstatic char sccsid[] = "@(#)trap.c	8.5 (Berkeley) 6/5/95";
3618334Speter#endif
3750654Sobrien#endif /* not lint */
3850654Sobrien#include <sys/cdefs.h>
3950654Sobrien__FBSDID("$FreeBSD: head/bin/sh/trap.c 157811 2006-04-17 17:55:11Z schweikh $");
4090285Sobrien
4190285Sobrien#include <signal.h>
4290285Sobrien#include <unistd.h>
4390285Sobrien#include <stdlib.h>
44169706Skan
45132744Skan#include "shell.h"
4690285Sobrien#include "main.h"
47169706Skan#include "nodes.h"	/* for other headers */
48132744Skan#include "eval.h"
4990285Sobrien#include "jobs.h"
5090285Sobrien#include "show.h"
5190285Sobrien#include "options.h"
5290285Sobrien#include "syntax.h"
5390285Sobrien#include "output.h"
5490285Sobrien#include "memalloc.h"
5590285Sobrien#include "error.h"
5690285Sobrien#include "trap.h"
5790285Sobrien#include "mystring.h"
5890285Sobrien#include "myhistedit.h"
5990285Sobrien
6090285Sobrien
6190285Sobrien/*
6290285Sobrien * Sigmode records the current value of the signal handlers for the various
6390285Sobrien * modes.  A value of zero means that the current handler is not known.
6490285Sobrien * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
6590285Sobrien */
6690285Sobrien
6790285Sobrien#define S_DFL 1			/* default signal handling (SIG_DFL) */
6890285Sobrien#define S_CATCH 2		/* signal is caught */
6990285Sobrien#define S_IGN 3			/* signal is ignored (SIG_IGN) */
7090285Sobrien#define S_HARD_IGN 4		/* signal is ignored permanently */
7190285Sobrien#define S_RESET 5		/* temporary - to reset a hard ignored sig */
7290285Sobrien
7390285Sobrien
7490285SobrienMKINIT char sigmode[NSIG];	/* current value of signal */
7590285Sobrienint pendingsigs;		/* indicates some signal received */
7690285Sobrienint in_dotrap;			/* do we execute in a trap handler? */
7790285Sobrienstatic char *volatile trap[NSIG];	/* trap handler commands */
7890285Sobrienstatic volatile sig_atomic_t gotsig[NSIG];
7990285Sobrien				/* indicates specified signal received */
80132744Skanstatic int ignore_sigchld;	/* Used while handling SIGCHLD traps. */
81117407Skanvolatile sig_atomic_t gotwinch;
82117407Skan
83117407Skanstatic int getsigaction(int, sig_t *);
84117407Skan
85117407Skan
86117407Skan/*
8750654Sobrien * Map a string to a signal number.
8850654Sobrien *
8990285Sobrien * Note: the signal number may exceed NSIG.
9050654Sobrien */
9118334Speterstatic int
9218334Spetersigstring_to_signum(char *sig)
9318334Speter{
9490285Sobrien
9518334Speter	if (is_number(sig)) {
96169706Skan		int signo;
9718334Speter
98169706Skan		signo = atoi(sig);
99169706Skan		return ((signo >= 0 && signo < NSIG) ? signo : (-1));
100169706Skan	} else if (strcasecmp(sig, "exit") == 0) {
101169706Skan		return (0);
102132744Skan	} else {
10318334Speter		int n;
104169706Skan
105117407Skan		if (strncasecmp(sig, "sig", 3) == 0)
106117407Skan			sig += 3;
107117407Skan		for (n = 1; n < sys_nsig; n++)
108117407Skan			if (sys_signame[n] &&
109169706Skan			    strcasecmp(sys_signame[n], sig) == 0)
110117407Skan				return (n);
111117407Skan	}
112117407Skan	return (-1);
113117407Skan}
114117407Skan
115117407Skan
116169706Skan/*
117169706Skan * Print a list of valid signal names.
118117407Skan */
11990285Sobrienstatic void
12090285Sobrienprintsignals(void)
12190285Sobrien{
12290285Sobrien	int n, outlen;
12390285Sobrien
124117407Skan	outlen = 0;
12518334Speter	for (n = 1; n < sys_nsig; n++) {
126169706Skan		if (sys_signame[n]) {
127169706Skan			out1fmt("%s", sys_signame[n]);
12852295Sobrien			outlen += strlen(sys_signame[n]);
129132744Skan		} else {
130132744Skan			out1fmt("%d", n);
131132744Skan			outlen += 3;	/* good enough */
132132744Skan		}
133219374Smm		++outlen;
134132744Skan		if (outlen > 70 || n == sys_nsig - 1) {
135132744Skan			out1str("\n");
136132744Skan			outlen = 0;
137132744Skan		} else {
138132744Skan			out1c(' ');
139169706Skan		}
140219374Smm	}
141169706Skan}
142169706Skan
143169706Skan
144132744Skan/*
145132744Skan * The trap builtin.
14652295Sobrien */
14752295Sobrienint
14890285Sobrientrapcmd(int argc, char **argv)
14990285Sobrien{
150169706Skan	char *action;
151169706Skan	int signo;
15290285Sobrien
153117407Skan	if (argc <= 1) {
15490285Sobrien		for (signo = 0 ; signo < sys_nsig ; signo++) {
15590285Sobrien			if (signo < NSIG && trap[signo] != NULL) {
15690285Sobrien				out1str("trap -- ");
15790285Sobrien				out1qstr(trap[signo]);
15890285Sobrien				if (signo == 0) {
15990285Sobrien					out1str(" exit\n");
160117407Skan				} else if (sys_signame[signo]) {
161169706Skan					out1fmt(" %s\n", sys_signame[signo]);
162132744Skan				} else {
163169706Skan					out1fmt(" %d\n", signo);
164169706Skan				}
165169706Skan			}
166237021Spfg		}
167169706Skan		return 0;
168169706Skan	}
169169706Skan	action = NULL;
170237021Spfg	if (*++argv && strcmp(*argv, "--") == 0)
17152295Sobrien		argv++;
172132744Skan	if (*argv && sigstring_to_signum(*argv) == -1) {
173132744Skan		if ((*argv)[0] != '-') {
174132744Skan			action = *argv;
175132744Skan			argv++;
176132744Skan		} else if ((*argv)[1] == '\0') {
17790285Sobrien			argv++;
17890285Sobrien		} else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
17990285Sobrien			printsignals();
180169706Skan			return 0;
181132744Skan		} else {
182132744Skan			error("bad option %s", *argv);
183132744Skan		}
184132744Skan	}
185132744Skan	while (*argv) {
186132744Skan		if ((signo = sigstring_to_signum(*argv)) == -1)
187169706Skan			error("bad signal %s", *argv);
188169706Skan		INTOFF;
189169706Skan		if (action)
190132744Skan			action = savestr(action);
191132744Skan		if (trap[signo])
192132744Skan			ckfree(trap[signo]);
193132744Skan		trap[signo] = action;
194132744Skan		if (signo != 0)
195132744Skan			setsignal(signo);
196132744Skan		INTON;
197132744Skan		argv++;
198132744Skan	}
199132744Skan	return 0;
200132744Skan}
201132744Skan
202132744Skan
203132744Skan/*
204132744Skan * Clear traps on a fork.
205132744Skan */
206132744Skanvoid
207132744Skanclear_traps(void)
208132744Skan{
209132744Skan	char *volatile *tp;
210169706Skan
211132744Skan	for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) {
212132744Skan		if (*tp && **tp) {	/* trap not NULL or SIG_IGN */
213132744Skan			INTOFF;
214132744Skan			ckfree(*tp);
215132744Skan			*tp = NULL;
21690285Sobrien			if (tp != &trap[0])
217132744Skan				setsignal(tp - trap);
218132744Skan			INTON;
219132744Skan		}
220132744Skan	}
221169706Skan}
222169706Skan
223169706Skan
224169706Skan/*
225169706Skan * Set the signal handler for the specified signal.  The routine figures
22652295Sobrien * out what it should be set to.
22790285Sobrien */
22890285Sobrienvoid
22990285Sobriensetsignal(int signo)
23090285Sobrien{
23190285Sobrien	int action;
23290285Sobrien	sig_t sig, sigact = SIG_DFL;
233117407Skan	char *t;
234169706Skan
235169706Skan	if ((t = trap[signo]) == NULL)
236117407Skan		action = S_DFL;
237117407Skan	else if (*t != '\0')
238169706Skan		action = S_CATCH;
239169706Skan	else
240237021Spfg		action = S_IGN;
241169706Skan	if (action == S_DFL) {
24296294Sobrien		switch (signo) {
243117407Skan		case SIGINT:
244117407Skan			action = S_CATCH;
24590285Sobrien			break;
246132744Skan		case SIGQUIT:
247132744Skan#ifdef DEBUG
248132744Skan			{
24990285Sobrien			extern int debug;
250117407Skan
251117407Skan			if (debug)
252117407Skan				break;
253117407Skan			}
25450654Sobrien#endif
255117407Skan			action = S_CATCH;
256117407Skan			break;
257117407Skan		case SIGTERM:
258117407Skan			if (rootshell && iflag)
25950654Sobrien				action = S_IGN;
260146908Skan			break;
261146908Skan#if JOBS
262146908Skan		case SIGTSTP:
263146908Skan		case SIGTTOU:
26418334Speter			if (rootshell && mflag)
26518334Speter				action = S_IGN;
26618334Speter			break;
26718334Speter#endif
26818334Speter#ifndef NO_HISTORY
26918334Speter		case SIGWINCH:
27018334Speter			if (rootshell && iflag)
27118334Speter				action = S_CATCH;
27218334Speter			break;
27318334Speter#endif
27418334Speter		}
27550654Sobrien	}
27690285Sobrien
27790285Sobrien	t = &sigmode[signo];
27850654Sobrien	if (*t == 0) {
279169706Skan		/*
280169706Skan		 * current setting unknown
281169706Skan		 */
282169706Skan		if (!getsigaction(signo, &sigact)) {
283169706Skan			/*
284169706Skan			 * Pretend it worked; maybe we should give a warning
285169706Skan			 * here, but other shells don't. We don't alter
286169706Skan			 * sigmode, so that we retry every time.
287169706Skan			 */
288169706Skan			return;
289169706Skan		}
290169706Skan		if (sigact == SIG_IGN) {
291169706Skan			if (mflag && (signo == SIGTSTP ||
292169706Skan			     signo == SIGTTIN || signo == SIGTTOU)) {
293132744Skan				*t = S_IGN;	/* don't hard ignore these */
294132744Skan			} else
295169706Skan				*t = S_HARD_IGN;
296169706Skan		} else {
297132744Skan			*t = S_RESET;	/* force to be set */
29850654Sobrien		}
29950654Sobrien	}
30050654Sobrien	if (*t == S_HARD_IGN || *t == action)
301169706Skan		return;
302132744Skan	switch (action) {
303132744Skan		case S_DFL:	sigact = SIG_DFL;	break;
304132744Skan		case S_CATCH:  	sigact = onsig;		break;
305132744Skan		case S_IGN:	sigact = SIG_IGN;	break;
306132744Skan	}
307132744Skan	*t = action;
308132744Skan	sig = signal(signo, sigact);
309132744Skan	if (sig != SIG_ERR && action == S_CATCH)
310132744Skan		siginterrupt(signo, 1);
311132744Skan}
312132744Skan
313132744Skan
31490285Sobrien/*
31590285Sobrien * Return the current setting for sig w/o changing it.
31690285Sobrien */
31790285Sobrienstatic int
318169706Skangetsigaction(int signo, sig_t *sigact)
319169706Skan{
320169706Skan	struct sigaction sa;
321169706Skan
322169706Skan	if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
323169706Skan		return 0;
324169706Skan	*sigact = (sig_t) sa.sa_handler;
325169706Skan	return 1;
32650654Sobrien}
327169706Skan
32818334Speter
329117407Skan/*
330117407Skan * Ignore a signal.
331117407Skan */
332117407Skanvoid
333117407Skanignoresig(int signo)
334132744Skan{
335117407Skan
336132744Skan	if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
337117407Skan		signal(signo, SIG_IGN);
338117407Skan	}
339117407Skan	sigmode[signo] = S_HARD_IGN;
340117407Skan}
341132744Skan
342132744Skan
343132744Skan#ifdef mkinit
344117407SkanINCLUDE <signal.h>
345117407SkanINCLUDE "trap.h"
346117407Skan
347117407SkanSHELLPROC {
348117407Skan	char *sm;
349117407Skan
350117407Skan	clear_traps();
351117407Skan	for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
352117407Skan		if (*sm == S_IGN)
353117407Skan			*sm = S_HARD_IGN;
354132744Skan	}
355132744Skan}
356117407Skan#endif
357117407Skan
358117407Skan
359117407Skan/*
360117407Skan * Signal handler.
361117407Skan */
362117407Skanvoid
363117407Skanonsig(int signo)
364132744Skan{
365117407Skan
366117407Skan	if (signo == SIGINT && trap[SIGINT] == NULL) {
367117407Skan		onint();
368117407Skan		return;
369117407Skan	}
370117407Skan
371132744Skan	if (signo != SIGCHLD || !ignore_sigchld)
372117407Skan		gotsig[signo] = 1;
373117407Skan	pendingsigs++;
374117407Skan
375117407Skan	/* If we are currently in a wait builtin, prepare to break it */
376117407Skan	if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0)
377117407Skan		breakwaitcmd = 1;
378117407Skan	/*
379117407Skan	 * If a trap is set, not ignored and not the null command, we need
380117407Skan	 * to make sure traps are executed even when a child blocks signals.
381219374Smm	 */
382219374Smm	if (Tflag &&
383219374Smm	    trap[signo] != NULL &&
384219374Smm	    ! (trap[signo][0] == '\0') &&
385117407Skan	    ! (trap[signo][0] == ':' && trap[signo][1] == '\0'))
386117407Skan		breakwaitcmd = 1;
387117407Skan
388132744Skan#ifndef NO_HISTORY
389117407Skan	if (signo == SIGWINCH)
390132744Skan		gotwinch = 1;
391117407Skan#endif
392117407Skan}
393117407Skan
394117407Skan
395117407Skan/*
396148163Sobrien * Called to execute a trap.  Perhaps we should avoid entering new trap
397148163Sobrien * handlers while we are executing a trap handler.
398117407Skan */
399117407Skanvoid
400132744Skandotrap(void)
401132744Skan{
402117407Skan	int i;
403117407Skan	int savestatus;
404169706Skan
405169706Skan	in_dotrap++;
406219374Smm	for (;;) {
407219374Smm		for (i = 1; i < NSIG; i++) {
408117407Skan			if (gotsig[i]) {
409117407Skan				gotsig[i] = 0;
410117407Skan				if (trap[i]) {
411117407Skan					/*
412117407Skan					 * Ignore SIGCHLD to avoid infinite
413117407Skan					 * recursion if the trap action does
414117407Skan					 * a fork.
415117407Skan					 */
416117407Skan					if (i == SIGCHLD)
417117407Skan						ignore_sigchld++;
418117407Skan					savestatus = exitstatus;
419132744Skan					evalstring(trap[i]);
420169706Skan					exitstatus = savestatus;
421219639Smm					if (i == SIGCHLD)
422219639Smm						ignore_sigchld--;
423117407Skan				}
424117407Skan				break;
425117407Skan			}
426117407Skan		}
427117407Skan		if (i >= NSIG)
428117407Skan			break;
429117407Skan	}
430117407Skan	in_dotrap--;
431117407Skan	pendingsigs = 0;
432117407Skan}
433117407Skan
434117407Skan
435117407Skan/*
436117407Skan * Controls whether the shell is interactive or not.
437117407Skan */
438117407Skanvoid
439117407Skansetinteractive(int on)
440117407Skan{
441117407Skan	static int is_interactive = -1;
442117407Skan
443117407Skan	if (on == is_interactive)
444117407Skan		return;
445117407Skan	setsignal(SIGINT);
446117407Skan	setsignal(SIGQUIT);
447117407Skan	setsignal(SIGTERM);
448117407Skan#ifndef NO_HISTORY
449117407Skan	setsignal(SIGWINCH);
450219374Smm#endif
451219374Smm	is_interactive = on;
452219374Smm}
453219374Smm
454219374Smm
455117407Skan/*
456117407Skan * Called to exit the shell.
457117407Skan */
458117407Skanvoid
459117407Skanexitshell(int status)
460117407Skan{
461117407Skan	struct jmploc loc1, loc2;
462117407Skan	char *p;
463117407Skan
464117407Skan	TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
465117407Skan	if (setjmp(loc1.loc)) {
466117407Skan		goto l1;
467117407Skan	}
468117407Skan	if (setjmp(loc2.loc)) {
469148163Sobrien		goto l2;
470148163Sobrien	}
471117407Skan	handler = &loc1;
472117407Skan	if ((p = trap[0]) != NULL && *p != '\0') {
473132744Skan		trap[0] = NULL;
474132744Skan		evalstring(p);
475132744Skan	}
476132744Skanl1:   handler = &loc2;			/* probably unnecessary */
477132744Skan	flushall();
478117407Skan#if JOBS
479117407Skan	setjobctl(0);
480117407Skan#endif
481117407Skanl2:   _exit(status);
482117407Skan}
483169706Skan