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