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