date and time created 95/05/04 17:59:12 by christos
[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
c74d53b6 12static 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
43extern char nullstr[1]; /* null string */
44
c74d53b6
KB
45char *trap[NSIG+1]; /* trap handler commands */
46MKINIT char sigmode[NSIG]; /* current value of signal */
47char gotsig[NSIG]; /* indicates specified signal received */
c23f21a1 48int pendingsigs; /* indicates some signal received */
cc410b67
KB
49
50/*
51 * The trap builtin.
52 */
53
54trapcmd(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
94void
95clear_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
117int
118setsignal(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 */
190sig_t
191getsigaction(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
204void
205ignoresig(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 214INCLUDE <signal.h>
cc410b67
KB
215INCLUDE "trap.h"
216
217SHELLPROC {
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
234void
235onsig(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
252void
253dotrap() {
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 }
269done:
270 pendingsigs = 0;
271}
272
273
274
275/*
276 * Controls whether the shell is interactive or not.
277 */
278
cc410b67
KB
279
280void
281setinteractive(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
298void
299exitshell(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 }
315l1: handler = &loc2; /* probably unnecessary */
316 flushall();
317#if JOBS
318 setjobctl(0);
319#endif
320l2: _exit(status);
321}