$ ); echo $? echoed 0,all other shells echo 2.
[unix-history] / usr / src / bin / sh / trap.c
CommitLineData
cc410b67 1/*-
d1b73048
KB
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
cc410b67
KB
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * %sccs.include.redist.c%
9 */
10
11#ifndef lint
13b3e634 12static char sccsid[] = "@(#)trap.c 8.3 (Berkeley) %G%";
cc410b67
KB
13#endif /* not lint */
14
13b3e634
CZ
15#include <signal.h>
16#include <unistd.h>
17#include <stdlib.h>
18
cc410b67
KB
19#include "shell.h"
20#include "main.h"
21#include "nodes.h" /* for other headers */
22#include "eval.h"
23#include "jobs.h"
13b3e634 24#include "show.h"
cc410b67
KB
25#include "options.h"
26#include "syntax.h"
cc410b67
KB
27#include "output.h"
28#include "memalloc.h"
29#include "error.h"
30#include "trap.h"
31#include "mystring.h"
cc410b67
KB
32
33
34/*
35 * Sigmode records the current value of the signal handlers for the various
36 * modes. A value of zero means that the current handler is not known.
37 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
38 */
39
40#define S_DFL 1 /* default signal handling (SIG_DFL) */
41#define S_CATCH 2 /* signal is caught */
42#define S_IGN 3 /* signal is ignored (SIG_IGN) */
43#define S_HARD_IGN 4 /* signal is ignored permenantly */
f91f1fb4 44#define S_RESET 5 /* temporary - to reset a hard ignored sig */
cc410b67
KB
45
46
47extern char nullstr[1]; /* null string */
48
c74d53b6
KB
49char *trap[NSIG+1]; /* trap handler commands */
50MKINIT char sigmode[NSIG]; /* current value of signal */
51char gotsig[NSIG]; /* indicates specified signal received */
c23f21a1 52int pendingsigs; /* indicates some signal received */
cc410b67
KB
53
54/*
55 * The trap builtin.
56 */
57
13b3e634
CZ
58int
59trapcmd(argc, argv)
60 int argc;
61 char **argv;
62{
cc410b67
KB
63 char *action;
64 char **ap;
65 int signo;
66
67 if (argc <= 1) {
c74d53b6 68 for (signo = 0 ; signo <= NSIG ; signo++) {
cc410b67
KB
69 if (trap[signo] != NULL)
70 out1fmt("%d: %s\n", signo, trap[signo]);
71 }
72 return 0;
73 }
74 ap = argv + 1;
75 if (is_number(*ap))
76 action = NULL;
77 else
78 action = *ap++;
79 while (*ap) {
c74d53b6 80 if ((signo = number(*ap)) < 0 || signo > NSIG)
cc410b67
KB
81 error("%s: bad trap", *ap);
82 INTOFF;
83 if (action)
84 action = savestr(action);
85 if (trap[signo])
86 ckfree(trap[signo]);
87 trap[signo] = action;
88 if (signo != 0)
89 setsignal(signo);
90 INTON;
91 ap++;
92 }
93 return 0;
94}
95
96
97
98/*
99 * Clear traps on a fork.
100 */
101
102void
103clear_traps() {
104 char **tp;
105
c74d53b6 106 for (tp = trap ; tp <= &trap[NSIG] ; tp++) {
cc410b67
KB
107 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
108 INTOFF;
109 ckfree(*tp);
110 *tp = NULL;
111 if (tp != &trap[0])
112 setsignal(tp - trap);
113 INTON;
114 }
115 }
116}
117
118
119
120/*
121 * Set the signal handler for the specified signal. The routine figures
122 * out what it should be set to.
123 */
124
13b3e634
CZ
125long
126setsignal(signo)
127 int signo;
128{
cc410b67 129 int action;
13b3e634 130 sig_t sigact = SIG_DFL;
cc410b67
KB
131 char *t;
132 extern void onsig();
f91f1fb4 133 extern sig_t getsigaction();
cc410b67
KB
134
135 if ((t = trap[signo]) == NULL)
136 action = S_DFL;
137 else if (*t != '\0')
138 action = S_CATCH;
139 else
140 action = S_IGN;
141 if (rootshell && action == S_DFL) {
142 switch (signo) {
143 case SIGINT:
144 if (iflag)
145 action = S_CATCH;
146 break;
cc410b67 147 case SIGQUIT:
c23f21a1
MT
148#ifdef DEBUG
149 {
150 extern int debug;
151
152 if (debug)
153 break;
154 }
cc410b67 155#endif
c23f21a1 156 /* FALLTHROUGH */
cc410b67
KB
157 case SIGTERM:
158 if (iflag)
159 action = S_IGN;
160 break;
161#if JOBS
162 case SIGTSTP:
163 case SIGTTOU:
b88df2e1 164 if (mflag)
cc410b67
KB
165 action = S_IGN;
166 break;
167#endif
168 }
169 }
170 t = &sigmode[signo - 1];
f91f1fb4
MT
171 if (*t == 0) {
172 /*
173 * current setting unknown
cc410b67 174 */
f91f1fb4 175 sigact = getsigaction(signo);
cc410b67 176 if (sigact == SIG_IGN) {
b88df2e1 177 if (mflag && (signo == SIGTSTP ||
f91f1fb4
MT
178 signo == SIGTTIN || signo == SIGTTOU)) {
179 *t = S_IGN; /* don't hard ignore these */
180 } else
181 *t = S_HARD_IGN;
cc410b67 182 } else {
f91f1fb4 183 *t = S_RESET; /* force to be set */
cc410b67
KB
184 }
185 }
186 if (*t == S_HARD_IGN || *t == action)
187 return 0;
188 switch (action) {
c23f21a1
MT
189 case S_DFL: sigact = SIG_DFL; break;
190 case S_CATCH: sigact = onsig; break;
191 case S_IGN: sigact = SIG_IGN; break;
cc410b67
KB
192 }
193 *t = action;
13b3e634 194 return (long)signal(signo, sigact);
cc410b67
KB
195}
196
f91f1fb4
MT
197/*
198 * Return the current setting for sig w/o changing it.
199 */
200sig_t
13b3e634
CZ
201getsigaction(signo)
202 int signo;
203{
f91f1fb4
MT
204 struct sigaction sa;
205
206 if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
207 error("Sigaction system call failed");
208
13b3e634 209 return (sig_t) sa.sa_handler;
f91f1fb4 210}
cc410b67 211
cc410b67
KB
212/*
213 * Ignore a signal.
214 */
215
216void
13b3e634
CZ
217ignoresig(signo)
218 int signo;
219{
cc410b67
KB
220 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
221 signal(signo, SIG_IGN);
222 }
223 sigmode[signo - 1] = S_HARD_IGN;
224}
225
226
227#ifdef mkinit
c74d53b6 228INCLUDE <signal.h>
cc410b67
KB
229INCLUDE "trap.h"
230
231SHELLPROC {
232 char *sm;
233
234 clear_traps();
c74d53b6 235 for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
cc410b67
KB
236 if (*sm == S_IGN)
237 *sm = S_HARD_IGN;
238 }
239}
240#endif
241
242
243
244/*
245 * Signal handler.
246 */
247
248void
13b3e634
CZ
249onsig(signo)
250 int signo;
251{
cc410b67
KB
252 signal(signo, onsig);
253 if (signo == SIGINT && trap[SIGINT] == NULL) {
254 onint();
255 return;
256 }
257 gotsig[signo - 1] = 1;
258 pendingsigs++;
259}
260
261
262
263/*
264 * Called to execute a trap. Perhaps we should avoid entering new trap
265 * handlers while we are executing a trap handler.
266 */
267
268void
269dotrap() {
270 int i;
c23f21a1 271 int savestatus;
cc410b67
KB
272
273 for (;;) {
274 for (i = 1 ; ; i++) {
275 if (gotsig[i - 1])
276 break;
c74d53b6 277 if (i >= NSIG)
cc410b67
KB
278 goto done;
279 }
280 gotsig[i - 1] = 0;
c23f21a1 281 savestatus=exitstatus;
cc410b67 282 evalstring(trap[i]);
c23f21a1 283 exitstatus=savestatus;
cc410b67
KB
284 }
285done:
286 pendingsigs = 0;
287}
288
289
290
291/*
292 * Controls whether the shell is interactive or not.
293 */
294
cc410b67
KB
295
296void
13b3e634
CZ
297setinteractive(on)
298 int on;
299{
b88df2e1
MT
300 static int is_interactive;
301
cc410b67
KB
302 if (on == is_interactive)
303 return;
304 setsignal(SIGINT);
305 setsignal(SIGQUIT);
306 setsignal(SIGTERM);
307 is_interactive = on;
308}
309
310
311
312/*
313 * Called to exit the shell.
314 */
315
316void
13b3e634
CZ
317exitshell(status)
318 int status;
319{
cc410b67
KB
320 struct jmploc loc1, loc2;
321 char *p;
322
323 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
b88df2e1
MT
324 if (setjmp(loc1.loc)) {
325 goto l1;
326 }
327 if (setjmp(loc2.loc)) {
328 goto l2;
329 }
cc410b67
KB
330 handler = &loc1;
331 if ((p = trap[0]) != NULL && *p != '\0') {
332 trap[0] = NULL;
333 evalstring(p);
334 }
335l1: handler = &loc2; /* probably unnecessary */
336 flushall();
337#if JOBS
338 setjobctl(0);
339#endif
340l2: _exit(status);
341}