off_t is now a quad. 0L looses.
[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
f91f1fb4 12static 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
44extern char nullstr[1]; /* null string */
45
46char *trap[MAXSIG+1]; /* trap handler commands */
47MKINIT char sigmode[MAXSIG]; /* current value of signal */
48char gotsig[MAXSIG]; /* indicates specified signal received */
c23f21a1 49int pendingsigs; /* indicates some signal received */
cc410b67
KB
50
51/*
52 * The trap builtin.
53 */
54
55trapcmd(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
95void
96clear_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
118int
119setsignal(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 */
191sig_t
192getsigaction(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
205void
206ignoresig(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
215INCLUDE "signames.h"
216INCLUDE "trap.h"
217
218SHELLPROC {
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
235void
236onsig(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
253void
254dotrap() {
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 }
270done:
271 pendingsigs = 0;
272}
273
274
275
276/*
277 * Controls whether the shell is interactive or not.
278 */
279
280int is_interactive;
281
282void
283setinteractive(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
298void
299exitshell(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 }
311l1: handler = &loc2; /* probably unnecessary */
312 flushall();
313#if JOBS
314 setjobctl(0);
315#endif
316l2: _exit(status);
317}