reenabled swaptest. quake should now load data and start on big endian architectures...
[AROS-Contrib.git] / gnu / abc-shell / trap.c
blobb9631c5100f8c041eb5c1724ff2016aed3ce0558
1 /*
2 * signal handling
3 */
5 /* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */
6 #define FROM_TRAP_C
7 #include "sh.h"
9 Trap sigtraps[NSIG+1] = {
10 { SIGEXIT_, "EXIT", "Signal 0" },
11 #include "siglist.h"
12 { SIGERR_, "ERR", "Error handler" },
15 static struct sigaction Sigact_ign, Sigact_trap;
17 void
18 inittraps(void)
20 sigemptyset(&Sigact_ign.sa_mask);
21 Sigact_ign.sa_flags = 0; /* interruptible */
22 Sigact_ign.sa_handler = SIG_IGN;
23 Sigact_trap = Sigact_ign;
24 Sigact_trap.sa_handler = trapsig;
26 sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR;
27 sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR;
28 sigtraps[SIGTERM].flags |= TF_DFL_INTR;/* not fatal for interactive */
29 sigtraps[SIGHUP].flags |= TF_FATAL;
30 sigtraps[SIGCHLD].flags |= TF_SHELL_USES;
32 /* these are always caught so we can clean up any temproary files. */
33 setsig(&sigtraps[SIGINT], trapsig, SS_RESTORE_ORIG);
34 setsig(&sigtraps[SIGQUIT], trapsig, SS_RESTORE_ORIG);
35 setsig(&sigtraps[SIGTERM], trapsig, SS_RESTORE_ORIG);
36 setsig(&sigtraps[SIGHUP], trapsig, SS_RESTORE_ORIG);
39 static void alarm_catcher(int sig);
41 void
42 alarm_init(void)
44 sigtraps[SIGALRM].flags |= TF_SHELL_USES;
45 setsig(&sigtraps[SIGALRM], alarm_catcher,
46 SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
49 static void
50 alarm_catcher(int sig)
52 int errno_ = errno;
54 if (ksh_tmout_state == TMOUT_READING) {
55 int left = alarm(0);
57 if (left == 0) {
58 ksh_tmout_state = TMOUT_LEAVING;
59 intrsig = 1;
60 } else
61 alarm(left);
63 errno = errno_;
64 return;
67 Trap *
68 gettrap(const char *name, int igncase)
70 int i;
71 Trap *p;
73 if (digit(*name)) {
74 int n;
76 if (getn(name, &n) && 0 <= n && n < NSIG)
77 return &sigtraps[n];
78 return NULL;
80 for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
81 if (p->name) {
82 if (igncase) {
83 if (p->name && (!strcasecmp(p->name, name) ||
84 (strlen(name) > 3 && !strncasecmp("SIG",
85 p->name, 3) &&
86 !strcasecmp(p->name, name + 3))))
87 return p;
88 } else {
89 if (p->name && (!strcmp(p->name, name) ||
90 (strlen(name) > 3 && !strncmp("SIG",
91 p->name, 3) && !strcmp(p->name, name + 3))))
92 return p;
95 return NULL;
99 * trap signal handler
101 void
102 trapsig(int i)
104 Trap *p = &sigtraps[i];
105 int errno_ = errno;
107 trap = p->set = 1;
108 if (p->flags & TF_DFL_INTR)
109 intrsig = 1;
110 if ((p->flags & TF_FATAL) && !p->trap) {
111 fatal_trap = 1;
112 intrsig = 1;
114 if (p->shtrap)
115 (*p->shtrap)(i);
116 errno = errno_;
117 if (sigtraps[i].cursig == trapsig) /* this for SIGCHLD,SIGALRM */
118 sigaction(i, &Sigact_trap, (struct sigaction *) 0);
119 return;
122 /* called when we want to allow the user to ^C out of something - won't
123 * work if user has trapped SIGINT.
125 void
126 intrcheck(void)
128 if (intrsig)
129 runtraps(TF_DFL_INTR|TF_FATAL);
132 /* called after EINTR to check if a signal with normally causes process
133 * termination has been received.
136 fatal_trap_check(void)
138 int i;
139 Trap *p;
141 /* todo: should check if signal is fatal, not the TF_DFL_INTR flag */
142 for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
143 if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL)))
144 /* return value is used as an exit code */
145 return 128 + p->signal;
146 return 0;
149 /* Returns the signal number of any pending traps: ie, a signal which has
150 * occurred for which a trap has been set or for which the TF_DFL_INTR flag
151 * is set.
154 trap_pending(void)
156 int i;
157 Trap *p;
159 for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
160 if (p->set && ((p->trap && p->trap[0]) ||
161 ((p->flags & (TF_DFL_INTR|TF_FATAL)) && !p->trap)))
162 return p->signal;
163 return 0;
167 * run any pending traps. If intr is set, only run traps that
168 * can interrupt commands.
170 void
171 runtraps(int flag)
173 int i;
174 Trap *p;
176 if (ksh_tmout_state == TMOUT_LEAVING) {
177 ksh_tmout_state = TMOUT_EXECUTING;
178 warningf(false, "timed out waiting for input");
179 unwind(LEXIT);
180 } else
181 /* XXX: this means the alarm will have no effect if a trap
182 * is caught after the alarm() was started...not good.
184 ksh_tmout_state = TMOUT_EXECUTING;
185 if (!flag)
186 trap = 0;
187 if (flag & TF_DFL_INTR)
188 intrsig = 0;
189 if (flag & TF_FATAL)
190 fatal_trap = 0;
191 for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
192 if (p->set && (!flag ||
193 ((p->flags & flag) && p->trap == (char *) 0)))
194 runtrap(p);
197 void
198 runtrap(Trap *p)
200 int i = p->signal;
201 char *trapstr = p->trap;
202 int oexstat;
203 int old_changed = 0;
205 p->set = 0;
206 if (trapstr == (char *) 0) { /* SIG_DFL */
207 if (p->flags & TF_FATAL) {
208 /* eg, SIGHUP */
209 exstat = 128 + i;
210 unwind(LLEAVE);
212 if (p->flags & TF_DFL_INTR) {
213 /* eg, SIGINT, SIGQUIT, SIGTERM, etc. */
214 exstat = 128 + i;
215 unwind(LINTR);
217 return;
219 if (trapstr[0] == '\0') /* SIG_IGN */
220 return;
221 if (i == SIGEXIT_ || i == SIGERR_) { /* avoid recursion on these */
222 old_changed = p->flags & TF_CHANGED;
223 p->flags &= ~TF_CHANGED;
224 p->trap = (char *) 0;
226 oexstat = exstat;
227 /* Note: trapstr is fully parsed before anything is executed, thus
228 * no problem with afree(p->trap) in settrap() while still in use.
230 command(trapstr);
231 exstat = oexstat;
232 if (i == SIGEXIT_ || i == SIGERR_) {
233 if (p->flags & TF_CHANGED)
234 /* don't clear TF_CHANGED */
235 afree(trapstr, APERM);
236 else
237 p->trap = trapstr;
238 p->flags |= old_changed;
242 /* clear pending traps and reset user's trap handlers; used after fork(2) */
243 void
244 cleartraps(void)
246 int i;
247 Trap *p;
249 trap = 0;
250 intrsig = 0;
251 fatal_trap = 0;
252 for (i = NSIG+1, p = sigtraps; --i >= 0; p++) {
253 p->set = 0;
254 if ((p->flags & TF_USER_SET) && (p->trap && p->trap[0]))
255 settrap(p, (char *) 0);
259 /* restore signals just before an exec(2) */
260 void
261 restoresigs(void)
263 int i;
264 Trap *p;
266 for (i = NSIG+1, p = sigtraps; --i >= 0; p++)
267 if (p->flags & (TF_EXEC_IGN|TF_EXEC_DFL))
268 setsig(p, (p->flags & TF_EXEC_IGN) ? SIG_IGN : SIG_DFL,
269 SS_RESTORE_CURR|SS_FORCE);
272 void
273 settrap(Trap *p, char *s)
275 sig_t f;
277 if (p->trap)
278 afree(p->trap, APERM);
279 p->trap = str_save(s, APERM); /* handles s == 0 */
280 p->flags |= TF_CHANGED;
281 f = !s ? SIG_DFL : s[0] ? trapsig : SIG_IGN;
283 p->flags |= TF_USER_SET;
284 if ((p->flags & (TF_DFL_INTR|TF_FATAL)) && f == SIG_DFL)
285 f = trapsig;
286 else if (p->flags & TF_SHELL_USES) {
287 if (!(p->flags & TF_ORIG_IGN) || Flag(FTALKING)) {
288 /* do what user wants at exec time */
289 p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
290 if (f == SIG_IGN)
291 p->flags |= TF_EXEC_IGN;
292 else
293 p->flags |= TF_EXEC_DFL;
295 /* assumes handler already set to what shell wants it
296 * (normally trapsig, but could be j_sigchld() or SIG_IGN)
298 return;
301 /* todo: should we let user know signal is ignored? how? */
302 setsig(p, f, SS_RESTORE_CURR|SS_USER);
305 /* Called by c_print() when writing to a co-process to ensure SIGPIPE won't
306 * kill shell (unless user catches it and exits)
309 block_pipe(void)
311 int restore_dfl = 0;
312 Trap *p = &sigtraps[SIGPIPE];
314 if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
315 setsig(p, SIG_IGN, SS_RESTORE_CURR);
316 if (p->flags & TF_ORIG_DFL)
317 restore_dfl = 1;
318 } else if (p->cursig == SIG_DFL) {
319 setsig(p, SIG_IGN, SS_RESTORE_CURR);
320 restore_dfl = 1; /* restore to SIG_DFL */
322 return restore_dfl;
325 /* Called by c_print() to undo whatever block_pipe() did */
326 void
327 restore_pipe(int restore_dfl)
329 if (restore_dfl)
330 setsig(&sigtraps[SIGPIPE], SIG_DFL, SS_RESTORE_CURR);
333 /* Set action for a signal. Action may not be set if original
334 * action was SIG_IGN, depending on the value of flags and
335 * FTALKING.
338 setsig(Trap *p, sig_t f, int flags)
340 struct sigaction sigact;
342 if (p->signal == SIGEXIT_ || p->signal == SIGERR_)
343 return 1;
345 /* First time setting this signal? If so, get and note the current
346 * setting.
348 if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
349 sigaction(p->signal, &Sigact_ign, &sigact);
350 p->flags |= sigact.sa_handler == SIG_IGN ?
351 TF_ORIG_IGN : TF_ORIG_DFL;
352 p->cursig = SIG_IGN;
355 /* Generally, an ignored signal stays ignored, except if
356 * - the user of an interactive shell wants to change it
357 * - the shell wants for force a change
359 if ((p->flags & TF_ORIG_IGN) && !(flags & SS_FORCE)
360 && (!(flags & SS_USER) || !Flag(FTALKING)))
361 return 0;
363 setexecsig(p, flags & SS_RESTORE_MASK);
365 /* This is here 'cause there should be a way of clearing shtraps, but
366 * don't know if this is a sane way of doing it. At the moment,
367 * all users of shtrap are lifetime users (SIGCHLD, SIGALRM, SIGWINCH).
369 if (!(flags & SS_USER))
370 p->shtrap = NULL;
371 if (flags & SS_SHTRAP) {
372 p->shtrap = f;
373 f = trapsig;
376 if (p->cursig != f) {
377 p->cursig = f;
378 sigemptyset(&sigact.sa_mask);
379 sigact.sa_flags = 0 /* interruptible */;
380 sigact.sa_handler = f;
381 sigaction(p->signal, &sigact, (struct sigaction *) 0);
384 return 1;
387 /* control what signal is set to before an exec() */
388 void
389 setexecsig(Trap *p, int restore)
391 /* XXX debugging */
392 if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL)))
393 internal_errorf(1, "setexecsig: unset signal %d(%s)",
394 p->signal, p->name);
396 /* restore original value for exec'd kids */
397 p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
398 switch (restore & SS_RESTORE_MASK) {
399 case SS_RESTORE_CURR: /* leave things as they currently are */
400 break;
401 case SS_RESTORE_ORIG:
402 p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL;
403 break;
404 case SS_RESTORE_DFL:
405 p->flags |= TF_EXEC_DFL;
406 break;
407 case SS_RESTORE_IGN:
408 p->flags |= TF_EXEC_IGN;
409 break;