1 /* $NetBSD: trap.c,v 1.33 2005/07/15 17:23:48 christos Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
38 static char sccsid
[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95";
40 __RCSID("$NetBSD: trap.c,v 1.33 2005/07/15 17:23:48 christos Exp $");
50 #include "nodes.h" /* for other headers */
65 * Sigmode records the current value of the signal handlers for the various
66 * modes. A value of zero means that the current handler is not known.
67 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
70 #define S_DFL 1 /* default signal handling (SIG_DFL) */
71 #define S_CATCH 2 /* signal is caught */
72 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
73 #define S_HARD_IGN 4 /* signal is ignored permenantly */
74 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
77 char *trap
[NSIG
+1]; /* trap handler commands */
78 MKINIT
char sigmode
[NSIG
]; /* current value of signal */
79 volatile char gotsig
[NSIG
]; /* indicates specified signal received */
80 int pendingsigs
; /* indicates some signal received */
82 static int getsigaction(int, sig_t
*);
85 * return the signal number described by `p' (as a number or a name)
86 * or -1 if it isn't one
90 signame_to_signum(const char *p
)
97 if (strcasecmp(p
, "exit") == 0 )
100 if (strncasecmp(p
, "sig", 3) == 0)
103 for (i
= 0; i
< NSIG
; ++i
)
104 if (strcasecmp (p
, sys_signame
[i
]) == 0)
110 * Print a list of valid signal names
119 for (n
= 1; n
< NSIG
; n
++) {
120 out1fmt("%s", sys_signame
[n
]);
121 if ((n
== NSIG
/2) || n
== (NSIG
- 1))
133 trapcmd(int argc
, char **argv
)
140 for (signo
= 0 ; signo
<= NSIG
; signo
++)
141 if (trap
[signo
] != NULL
) {
143 print_quoted(trap
[signo
]);
145 (signo
) ? sys_signame
[signo
] : "EXIT");
153 if (strcmp(*ap
, "--") == 0)
157 if (signame_to_signum(*ap
) == -1) {
158 if ((*ap
)[0] == '-') {
159 if ((*ap
)[1] == '\0')
161 else if ((*ap
)[1] == 'l' && (*ap
)[2] == '\0') {
166 error("bad option %s\n", *ap
);
176 signo
= signame_to_signum(*ap
);
178 if (signo
< 0 || signo
> NSIG
)
179 error("%s: bad trap", *ap
);
183 action
= savestr(action
);
188 trap
[signo
] = action
;
201 * Clear traps on a fork or vfork.
202 * Takes one arg vfork, to tell it to not be destructive of
203 * the parents variables.
207 clear_traps(int vforked
)
211 for (tp
= trap
; tp
<= &trap
[NSIG
] ; tp
++) {
212 if (*tp
&& **tp
) { /* trap not NULL or SIG_IGN */
219 setsignal(tp
- trap
, vforked
);
228 * Set the signal handler for the specified signal. The routine figures
229 * out what it should be set to.
233 setsignal(int signo
, int vforked
)
236 sig_t sigact
= SIG_DFL
, sig
;
239 if ((t
= trap
[signo
]) == NULL
)
245 if (rootshell
&& !vforked
&& action
== S_DFL
) {
248 if (iflag
|| minusc
|| sflag
== 0)
271 t
= &sigmode
[signo
- 1];
275 * current setting unknown
277 if (!getsigaction(signo
, &sigact
)) {
279 * Pretend it worked; maybe we should give a warning
280 * here, but other shells don't. We don't alter
281 * sigmode, so that we retry every time.
285 if (sigact
== SIG_IGN
) {
287 * POSIX 3.14.13 states that non-interactive shells
288 * should ignore trap commands for signals that were
289 * ignored upon entry, and leaves the behavior
290 * unspecified for interactive shells. On interactive
291 * shells, or if job control is on, and we have a job
292 * control related signal, we allow the trap to work.
294 * This change allows us to be POSIX compliant, and
295 * at the same time override the default behavior if
296 * we need to by setting the interactive flag.
298 if ((mflag
&& (signo
== SIGTSTP
||
299 signo
== SIGTTIN
|| signo
== SIGTTOU
)) || iflag
) {
304 tsig
= S_RESET
; /* force to be set */
307 if (tsig
== S_HARD_IGN
|| tsig
== action
)
310 case S_DFL
: sigact
= SIG_DFL
; break;
311 case S_CATCH
: sigact
= onsig
; break;
312 case S_IGN
: sigact
= SIG_IGN
; break;
314 sig
= signal(signo
, sigact
);
315 if (sig
!= SIG_ERR
) {
319 if (action
== S_CATCH
)
320 (void)siginterrupt(signo
, 1);
322 * If our parent accidentally blocked signals for
323 * us make sure we unblock them
325 (void)sigemptyset(&ss
);
326 (void)sigaddset(&ss
, signo
);
327 (void)sigprocmask(SIG_UNBLOCK
, &ss
, NULL
);
333 * Return the current setting for sig w/o changing it.
336 getsigaction(int signo
, sig_t
*sigact
)
340 if (sigaction(signo
, (struct sigaction
*)0, &sa
) == -1)
342 *sigact
= (sig_t
) sa
.sa_handler
;
351 ignoresig(int signo
, int vforked
)
353 if (sigmode
[signo
- 1] != S_IGN
&& sigmode
[signo
- 1] != S_HARD_IGN
) {
354 signal(signo
, SIG_IGN
);
357 sigmode
[signo
- 1] = S_HARD_IGN
;
369 for (sm
= sigmode
; sm
< sigmode
+ NSIG
; sm
++) {
385 signal(signo
, onsig
);
386 if (signo
== SIGINT
&& trap
[SIGINT
] == NULL
) {
390 gotsig
[signo
- 1] = 1;
397 * Called to execute a trap. Perhaps we should avoid entering new trap
398 * handlers while we are executing a trap handler.
408 for (i
= 1 ; ; i
++) {
415 savestatus
=exitstatus
;
416 evalstring(trap
[i
], 0);
417 exitstatus
=savestatus
;
426 * Controls whether the shell is interactive or not.
431 setinteractive(int on
)
433 static int is_interactive
;
435 if (on
== is_interactive
)
437 setsignal(SIGINT
, 0);
438 setsignal(SIGQUIT
, 0);
439 setsignal(SIGTERM
, 0);
446 * Called to exit the shell.
450 exitshell(int status
)
452 struct jmploc loc1
, loc2
;
455 TRACE(("pid %d, exitshell(%d)\n", getpid(), status
));
456 if (setjmp(loc1
.loc
)) {
459 if (setjmp(loc2
.loc
)) {
463 if ((p
= trap
[0]) != NULL
&& *p
!= '\0') {
467 l1
: handler
= &loc2
; /* probably unnecessary */