xref: /original-bsd/bin/sh/trap.c (revision 3d11fed5)
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
12 static char sccsid[] = "@(#)trap.c	5.2 (Berkeley) 04/12/91";
13 #endif /* not lint */
14 
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 */
41 
42 
43 extern char nullstr[1];		/* null string */
44 
45 char *trap[MAXSIG+1];		/* trap handler commands */
46 MKINIT char sigmode[MAXSIG];	/* current value of signal */
47 char gotsig[MAXSIG];		/* indicates specified signal received */
48 int pendingsigs;			/* indicates some signal received */
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) {
60 		for (signo = 0 ; signo <= MAXSIG ; signo++) {
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) {
72 		if ((signo = number(*ap)) < 0 || signo > MAXSIG)
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 
98 	for (tp = trap ; tp <= &trap[MAXSIG] ; tp++) {
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();
123 
124 	if ((t = trap[signo]) == NULL)
125 		action = S_DFL;
126 	else if (*t != '\0')
127 		action = S_CATCH;
128 	else
129 		action = S_IGN;
130 	if (rootshell && action == S_DFL) {
131 		switch (signo) {
132 		case SIGINT:
133 			if (iflag)
134 				action = S_CATCH;
135 			break;
136 		case SIGQUIT:
137 #ifdef DEBUG
138 			{
139 			extern int debug;
140 
141 			if (debug)
142 				break;
143 			}
144 #endif
145 			/* FALLTHROUGH */
146 		case SIGTERM:
147 			if (iflag)
148 				action = S_IGN;
149 			break;
150 #if JOBS
151 		case SIGTSTP:
152 		case SIGTTOU:
153 			if (jflag)
154 				action = S_IGN;
155 			break;
156 #endif
157 		}
158 	}
159 	t = &sigmode[signo - 1];
160 	if (*t == 0) {	/* current setting unknown */
161 		/*
162 		 * There is a race condition here if action is not S_IGN.
163 		 * A signal can be ignored that shouldn't be.
164 		 */
165 		if ((int)(sigact = signal(signo, SIG_IGN)) == -1)
166 			error("Signal system call failed");
167 		if (sigact == SIG_IGN) {
168 			*t = S_HARD_IGN;
169 		} else {
170 			*t = S_IGN;
171 		}
172 	}
173 	if (*t == S_HARD_IGN || *t == action)
174 		return 0;
175 	switch (action) {
176 		case S_DFL:	sigact = SIG_DFL;	break;
177 		case S_CATCH:  	sigact = onsig;		break;
178 		case S_IGN:	sigact = SIG_IGN;	break;
179 	}
180 	*t = action;
181 	return (int)signal(signo, sigact);
182 }
183 
184 
185 /*
186  * Ignore a signal.
187  */
188 
189 void
190 ignoresig(signo) {
191 	if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
192 		signal(signo, SIG_IGN);
193 	}
194 	sigmode[signo - 1] = S_HARD_IGN;
195 }
196 
197 
198 #ifdef mkinit
199 INCLUDE "signames.h"
200 INCLUDE "trap.h"
201 
202 SHELLPROC {
203 	char *sm;
204 
205 	clear_traps();
206 	for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) {
207 		if (*sm == S_IGN)
208 			*sm = S_HARD_IGN;
209 	}
210 }
211 #endif
212 
213 
214 
215 /*
216  * Signal handler.
217  */
218 
219 void
220 onsig(signo) {
221 	signal(signo, onsig);
222 	if (signo == SIGINT && trap[SIGINT] == NULL) {
223 		onint();
224 		return;
225 	}
226 	gotsig[signo - 1] = 1;
227 	pendingsigs++;
228 }
229 
230 
231 
232 /*
233  * Called to execute a trap.  Perhaps we should avoid entering new trap
234  * handlers while we are executing a trap handler.
235  */
236 
237 void
238 dotrap() {
239 	int i;
240 	int savestatus;
241 
242 	for (;;) {
243 		for (i = 1 ; ; i++) {
244 			if (gotsig[i - 1])
245 				break;
246 			if (i >= MAXSIG)
247 				goto done;
248 		}
249 		gotsig[i - 1] = 0;
250 		savestatus=exitstatus;
251 		evalstring(trap[i]);
252 		exitstatus=savestatus;
253 	}
254 done:
255 	pendingsigs = 0;
256 }
257 
258 
259 
260 /*
261  * Controls whether the shell is interactive or not.
262  */
263 
264 int is_interactive;
265 
266 void
267 setinteractive(on) {
268 	if (on == is_interactive)
269 		return;
270 	setsignal(SIGINT);
271 	setsignal(SIGQUIT);
272 	setsignal(SIGTERM);
273 	is_interactive = on;
274 }
275 
276 
277 
278 /*
279  * Called to exit the shell.
280  */
281 
282 void
283 exitshell(status) {
284 	struct jmploc loc1, loc2;
285 	char *p;
286 
287 	TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
288 	if (setjmp(loc1.loc))  goto l1;
289 	if (setjmp(loc2.loc))  goto l2;
290 	handler = &loc1;
291 	if ((p = trap[0]) != NULL && *p != '\0') {
292 		trap[0] = NULL;
293 		evalstring(p);
294 	}
295 l1:   handler = &loc2;			/* probably unnecessary */
296 	flushall();
297 #if JOBS
298 	setjobctl(0);
299 #endif
300 l2:   _exit(status);
301 }
302