1 /* $NetBSD: trap.c,v 1.37 2015/08/22 12:12:47 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.37 2015/08/22 12:12:47 christos Exp $");
50 #include "nodes.h" /* for other headers */
66 * Sigmode records the current value of the signal handlers for the various
67 * modes. A value of zero means that the current handler is not known.
68 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
71 #define S_DFL 1 /* default signal handling (SIG_DFL) */
72 #define S_CATCH 2 /* signal is caught */
73 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
74 #define S_HARD_IGN 4 /* signal is ignored permenantly */
75 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
78 char *trap
[NSIG
+1]; /* trap handler commands */
79 MKINIT
char sigmode
[NSIG
]; /* current value of signal */
80 static volatile char gotsig
[NSIG
];/* indicates specified signal received */
81 volatile int pendingsigs
; /* indicates some signal received */
83 static int getsigaction(int, sig_t
*);
86 * return the signal number described by `p' (as a number or a name)
87 * or -1 if it isn't one
91 signame_to_signum(const char *p
)
98 if (strcasecmp(p
, "exit") == 0 )
101 if (strncasecmp(p
, "sig", 3) == 0)
104 for (i
= 0; i
< NSIG
; ++i
)
105 if (strcasecmp (p
, sys_signame
[i
]) == 0)
111 * Print a list of valid signal names
120 for (n
= 1; n
< NSIG
; n
++) {
121 out1fmt("%s", sys_signame
[n
]);
122 if ((n
== NSIG
/2) || n
== (NSIG
- 1))
134 trapcmd(int argc
, char **argv
)
141 for (signo
= 0 ; signo
<= NSIG
; signo
++)
142 if (trap
[signo
] != NULL
) {
144 print_quoted(trap
[signo
]);
146 (signo
) ? sys_signame
[signo
] : "EXIT");
154 if (strcmp(*ap
, "--") == 0)
158 if (signame_to_signum(*ap
) == -1) {
159 if ((*ap
)[0] == '-') {
160 if ((*ap
)[1] == '\0')
162 else if ((*ap
)[1] == 'l' && (*ap
)[2] == '\0') {
167 error("bad option %s\n", *ap
);
177 signo
= signame_to_signum(*ap
);
179 if (signo
< 0 || signo
> NSIG
)
180 error("%s: bad trap", *ap
);
184 action
= savestr(action
);
189 trap
[signo
] = action
;
202 * Clear traps on a fork or vfork.
203 * Takes one arg vfork, to tell it to not be destructive of
204 * the parents variables.
208 clear_traps(int vforked
)
212 for (tp
= trap
; tp
<= &trap
[NSIG
] ; tp
++) {
213 if (*tp
&& **tp
) { /* trap not NULL or SIG_IGN */
220 setsignal(tp
- trap
, vforked
);
229 * Set the signal handler for the specified signal. The routine figures
230 * out what it should be set to.
234 setsignal(int signo
, int vforked
)
237 sig_t sigact
= SIG_DFL
, sig
;
240 if ((t
= trap
[signo
]) == NULL
)
246 if (rootshell
&& !vforked
&& action
== S_DFL
) {
249 if (iflag
|| minusc
|| sflag
== 0)
272 t
= &sigmode
[signo
- 1];
276 * current setting unknown
278 if (!getsigaction(signo
, &sigact
)) {
280 * Pretend it worked; maybe we should give a warning
281 * here, but other shells don't. We don't alter
282 * sigmode, so that we retry every time.
286 if (sigact
== SIG_IGN
) {
288 * POSIX 3.14.13 states that non-interactive shells
289 * should ignore trap commands for signals that were
290 * ignored upon entry, and leaves the behavior
291 * unspecified for interactive shells. On interactive
292 * shells, or if job control is on, and we have a job
293 * control related signal, we allow the trap to work.
295 * This change allows us to be POSIX compliant, and
296 * at the same time override the default behavior if
297 * we need to by setting the interactive flag.
299 if ((mflag
&& (signo
== SIGTSTP
||
300 signo
== SIGTTIN
|| signo
== SIGTTOU
)) || iflag
) {
305 tsig
= S_RESET
; /* force to be set */
308 if (tsig
== S_HARD_IGN
|| tsig
== action
)
311 case S_DFL
: sigact
= SIG_DFL
; break;
312 case S_CATCH
: sigact
= onsig
; break;
313 case S_IGN
: sigact
= SIG_IGN
; break;
315 sig
= signal(signo
, sigact
);
316 if (sig
!= SIG_ERR
) {
320 if (action
== S_CATCH
)
321 (void)siginterrupt(signo
, 1);
323 * If our parent accidentally blocked signals for
324 * us make sure we unblock them
326 (void)sigemptyset(&ss
);
327 (void)sigaddset(&ss
, signo
);
328 (void)sigprocmask(SIG_UNBLOCK
, &ss
, NULL
);
334 * Return the current setting for sig w/o changing it.
337 getsigaction(int signo
, sig_t
*sigact
)
341 if (sigaction(signo
, (struct sigaction
*)0, &sa
) == -1)
343 *sigact
= (sig_t
) sa
.sa_handler
;
352 ignoresig(int signo
, int vforked
)
354 if (sigmode
[signo
- 1] != S_IGN
&& sigmode
[signo
- 1] != S_HARD_IGN
) {
355 signal(signo
, SIG_IGN
);
358 sigmode
[signo
- 1] = S_HARD_IGN
;
370 for (sm
= sigmode
; sm
< sigmode
+ NSIG
; sm
++) {
386 signal(signo
, onsig
);
387 if (signo
== SIGINT
&& trap
[SIGINT
] == NULL
) {
391 gotsig
[signo
- 1] = 1;
398 * Called to execute a trap. Perhaps we should avoid entering new trap
399 * handlers while we are executing a trap handler.
409 for (i
= 1 ; ; i
++) {
416 savestatus
=exitstatus
;
417 evalstring(trap
[i
], 0);
418 exitstatus
=savestatus
;
429 for (i
= NSIG
; i
> 0; i
--)
432 return SIGINT
; /* XXX */
436 * Controls whether the shell is interactive or not.
441 setinteractive(int on
)
443 static int is_interactive
;
445 if (on
== is_interactive
)
447 setsignal(SIGINT
, 0);
448 setsignal(SIGQUIT
, 0);
449 setsignal(SIGTERM
, 0);
456 * Called to exit the shell.
460 exitshell(int status
)
462 struct jmploc loc1
, loc2
;
465 TRACE(("pid %d, exitshell(%d)\n", getpid(), status
));
466 if (setjmp(loc1
.loc
)) {
469 if (setjmp(loc2
.loc
)) {
473 if ((p
= trap
[0]) != NULL
&& *p
!= '\0') {
477 l1
: handler
= &loc2
; /* probably unnecessary */