Commit | Line | Data |
---|---|---|
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 | 12 | static 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 | ||
47 | extern char nullstr[1]; /* null string */ | |
48 | ||
c74d53b6 KB |
49 | char *trap[NSIG+1]; /* trap handler commands */ |
50 | MKINIT char sigmode[NSIG]; /* current value of signal */ | |
51 | char gotsig[NSIG]; /* indicates specified signal received */ | |
c23f21a1 | 52 | int pendingsigs; /* indicates some signal received */ |
cc410b67 KB |
53 | |
54 | /* | |
55 | * The trap builtin. | |
56 | */ | |
57 | ||
13b3e634 CZ |
58 | int |
59 | trapcmd(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 | ||
102 | void | |
103 | clear_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 |
125 | long |
126 | setsignal(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 | */ | |
200 | sig_t | |
13b3e634 CZ |
201 | getsigaction(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 | ||
216 | void | |
13b3e634 CZ |
217 | ignoresig(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 | 228 | INCLUDE <signal.h> |
cc410b67 KB |
229 | INCLUDE "trap.h" |
230 | ||
231 | SHELLPROC { | |
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 | ||
248 | void | |
13b3e634 CZ |
249 | onsig(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 | ||
268 | void | |
269 | dotrap() { | |
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 | } |
285 | done: | |
286 | pendingsigs = 0; | |
287 | } | |
288 | ||
289 | ||
290 | ||
291 | /* | |
292 | * Controls whether the shell is interactive or not. | |
293 | */ | |
294 | ||
cc410b67 KB |
295 | |
296 | void | |
13b3e634 CZ |
297 | setinteractive(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 | ||
316 | void | |
13b3e634 CZ |
317 | exitshell(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 | } | |
335 | l1: handler = &loc2; /* probably unnecessary */ | |
336 | flushall(); | |
337 | #if JOBS | |
338 | setjobctl(0); | |
339 | #endif | |
340 | l2: _exit(status); | |
341 | } |