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