1 /* $NetBSD: trap.c,v 1.7 2006/05/13 21:54:13 christos Exp $ */
9 __RCSID("$NetBSD: trap.c,v 1.7 2006/05/13 21:54:13 christos Exp $");
13 /* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */
17 /* Table is indexed by signal number
19 * The script siglist.sh generates siglist.out, which is a sorted, complete
22 Trap sigtraps
[SIGNALS
+1] = {
23 { .signal
= SIGEXIT_
, .name
= "EXIT", .mess
= "Signal 0" },
24 #include "siglist.out" /* generated by siglist.sh */
25 { .signal
= SIGERR_
, .name
= "ERR", .mess
= "Error handler" },
28 static struct sigaction Sigact_ign
, Sigact_trap
;
33 #ifdef HAVE_SYS_SIGLIST
34 # ifndef SYS_SIGLIST_DECLARED
35 extern char *sys_siglist
[];
39 /* Use system description, if available, for unknown signals... */
40 for (i
= 0; i
< NSIG
; i
++)
41 if (!sigtraps
[i
].name
&& sys_siglist
[i
] && sys_siglist
[i
][0])
42 sigtraps
[i
].mess
= sys_siglist
[i
];
43 #endif /* HAVE_SYS_SIGLIST */
45 sigemptyset(&Sigact_ign
.sa_mask
);
46 Sigact_ign
.sa_flags
= KSH_SA_FLAGS
;
47 Sigact_ign
.sa_handler
= SIG_IGN
;
48 Sigact_trap
= Sigact_ign
;
49 Sigact_trap
.sa_handler
= trapsig
;
51 sigtraps
[SIGINT
].flags
|= TF_DFL_INTR
| TF_TTY_INTR
;
52 sigtraps
[SIGQUIT
].flags
|= TF_DFL_INTR
| TF_TTY_INTR
;
53 sigtraps
[SIGTERM
].flags
|= TF_DFL_INTR
;/* not fatal for interactive */
54 sigtraps
[SIGHUP
].flags
|= TF_FATAL
;
55 sigtraps
[SIGCHLD
].flags
|= TF_SHELL_USES
;
57 /* these are always caught so we can clean up any temporary files. */
58 setsig(&sigtraps
[SIGINT
], trapsig
, SS_RESTORE_ORIG
);
59 setsig(&sigtraps
[SIGQUIT
], trapsig
, SS_RESTORE_ORIG
);
60 setsig(&sigtraps
[SIGTERM
], trapsig
, SS_RESTORE_ORIG
);
61 setsig(&sigtraps
[SIGHUP
], trapsig
, SS_RESTORE_ORIG
);
65 static RETSIGTYPE alarm_catcher
ARGS((int sig
));
70 sigtraps
[SIGALRM
].flags
|= TF_SHELL_USES
;
71 setsig(&sigtraps
[SIGALRM
], alarm_catcher
,
72 SS_RESTORE_ORIG
|SS_FORCE
|SS_SHTRAP
);
81 if (ksh_tmout_state
== TMOUT_READING
) {
85 ksh_tmout_state
= TMOUT_LEAVING
;
96 gettrap(name
, igncase
)
106 if (getn(name
, &n
) && 0 <= n
&& n
< SIGNALS
)
110 for (p
= sigtraps
, i
= SIGNALS
+1; --i
>= 0; p
++)
113 if (p
->name
&& (!strcasecmp(p
->name
, name
) ||
114 (strlen(name
) > 3 && !strncasecmp("SIG",
116 !strcasecmp(p
->name
, name
+ 3))))
119 if (p
->name
&& (!strcmp(p
->name
, name
) ||
120 (strlen(name
) > 3 && !strncmp("SIG",
121 p
->name
, 3) && !strcmp(p
->name
, name
+ 3))))
129 * trap signal handler
135 Trap
*p
= &sigtraps
[i
];
139 if (p
->flags
& TF_DFL_INTR
)
141 if ((p
->flags
& TF_FATAL
) && !p
->trap
) {
148 if (sigtraps
[i
].cursig
== trapsig
) /* this for SIGCHLD,SIGALRM */
149 sigaction(i
, &Sigact_trap
, (struct sigaction
*) 0);
150 #endif /* V7_SIGNALS */
155 /* called when we want to allow the user to ^C out of something - won't
156 * work if user has trapped SIGINT.
162 runtraps(TF_DFL_INTR
|TF_FATAL
);
165 /* called after EINTR to check if a signal with normally causes process
166 * termination has been received.
174 /* todo: should check if signal is fatal, not the TF_DFL_INTR flag */
175 for (p
= sigtraps
, i
= SIGNALS
+1; --i
>= 0; p
++)
176 if (p
->set
&& (p
->flags
& (TF_DFL_INTR
|TF_FATAL
)))
177 /* return value is used as an exit code */
178 return 128 + p
->signal
;
182 /* Returns the signal number of any pending traps: ie, a signal which has
183 * occurred for which a trap has been set or for which the TF_DFL_INTR flag
192 for (p
= sigtraps
, i
= SIGNALS
+1; --i
>= 0; p
++)
193 if (p
->set
&& ((p
->trap
&& p
->trap
[0])
194 || ((p
->flags
& (TF_DFL_INTR
|TF_FATAL
))
201 * run any pending traps. If intr is set, only run traps that
202 * can interrupt commands.
212 if (ksh_tmout_state
== TMOUT_LEAVING
) {
213 ksh_tmout_state
= TMOUT_EXECUTING
;
214 warningf(FALSE
, "timed out waiting for input");
217 /* XXX: this means the alarm will have no effect if a trap
218 * is caught after the alarm() was started...not good.
220 ksh_tmout_state
= TMOUT_EXECUTING
;
224 if (flag
& TF_DFL_INTR
)
228 for (p
= sigtraps
, i
= SIGNALS
+1; --i
>= 0; p
++)
230 || ((p
->flags
& flag
) && p
->trap
== (char *) 0)))
239 char *trapstr
= p
->trap
;
241 int UNINITIALIZED(old_changed
);
244 if (trapstr
== (char *) 0) { /* SIG_DFL */
245 if (p
->flags
& TF_FATAL
) {
250 if (p
->flags
& TF_DFL_INTR
) {
251 /* eg, SIGINT, SIGQUIT, SIGTERM, etc. */
257 if (trapstr
[0] == '\0') /* SIG_IGN */
259 if (i
== SIGEXIT_
|| i
== SIGERR_
) { /* avoid recursion on these */
260 old_changed
= p
->flags
& TF_CHANGED
;
261 p
->flags
&= ~TF_CHANGED
;
262 p
->trap
= (char *) 0;
265 /* Note: trapstr is fully parsed before anything is executed, thus
266 * no problem with afree(p->trap) in settrap() while still in use.
270 if (i
== SIGEXIT_
|| i
== SIGERR_
) {
271 if (p
->flags
& TF_CHANGED
)
272 /* don't clear TF_CHANGED */
273 afree(trapstr
, APERM
);
276 p
->flags
|= old_changed
;
280 /* clear pending traps and reset user's trap handlers; used after fork(2) */
290 for (i
= SIGNALS
+1, p
= sigtraps
; --i
>= 0; p
++) {
292 if ((p
->flags
& TF_USER_SET
) && (p
->trap
&& p
->trap
[0]))
293 settrap(p
, (char *) 0);
297 /* restore signals just before an exec(2) */
304 for (i
= SIGNALS
+1, p
= sigtraps
; --i
>= 0; p
++)
305 if (p
->flags
& (TF_EXEC_IGN
|TF_EXEC_DFL
))
306 setsig(p
, (p
->flags
& TF_EXEC_IGN
) ? SIG_IGN
: SIG_DFL
,
307 SS_RESTORE_CURR
|SS_FORCE
);
318 afree(p
->trap
, APERM
);
319 p
->flags
|= TF_CHANGED
|TF_USER_SET
;
321 p
->trap
= str_save(s
, APERM
);
322 f
= s
[0] ? trapsig
: SIG_IGN
;
327 if ((p
->flags
& (TF_DFL_INTR
|TF_FATAL
)) && f
== SIG_DFL
)
329 else if (p
->flags
& TF_SHELL_USES
) {
330 if (!(p
->flags
& TF_ORIG_IGN
) || Flag(FTALKING
)) {
331 /* do what user wants at exec time */
332 p
->flags
&= ~(TF_EXEC_IGN
|TF_EXEC_DFL
);
334 p
->flags
|= TF_EXEC_IGN
;
336 p
->flags
|= TF_EXEC_DFL
;
338 /* assumes handler already set to what shell wants it
339 * (normally trapsig, but could be j_sigchld() or SIG_IGN)
344 /* todo: should we let user know signal is ignored? how? */
345 setsig(p
, f
, SS_RESTORE_CURR
|SS_USER
);
348 /* Called by c_print() when writing to a co-process to ensure SIGPIPE won't
349 * kill shell (unless user catches it and exits)
355 Trap
*p
= &sigtraps
[SIGPIPE
];
357 if (!(p
->flags
& (TF_ORIG_IGN
|TF_ORIG_DFL
))) {
358 setsig(p
, SIG_IGN
, SS_RESTORE_CURR
);
359 if (p
->flags
& TF_ORIG_DFL
)
361 } else if (p
->cursig
== SIG_DFL
) {
362 setsig(p
, SIG_IGN
, SS_RESTORE_CURR
);
363 restore_dfl
= 1; /* restore to SIG_DFL */
368 /* Called by c_print() to undo whatever block_pipe() did */
370 restore_pipe(restore_dfl
)
374 setsig(&sigtraps
[SIGPIPE
], SIG_DFL
, SS_RESTORE_CURR
);
377 /* Set action for a signal. Action may not be set if original
378 * action was SIG_IGN, depending on the value of flags and
387 struct sigaction sigact
;
389 if (p
->signal
== SIGEXIT_
|| p
->signal
== SIGERR_
)
392 /* First time setting this signal? If so, get and note the current
395 if (!(p
->flags
& (TF_ORIG_IGN
|TF_ORIG_DFL
))) {
396 sigaction(p
->signal
, &Sigact_ign
, &sigact
);
397 p
->flags
|= sigact
.sa_handler
== SIG_IGN
?
398 TF_ORIG_IGN
: TF_ORIG_DFL
;
402 /* Generally, an ignored signal stays ignored, except if
403 * - the user of an interactive shell wants to change it
404 * - the shell wants for force a change
406 if ((p
->flags
& TF_ORIG_IGN
) && !(flags
& SS_FORCE
)
407 && (!(flags
& SS_USER
) || !Flag(FTALKING
)))
410 setexecsig(p
, flags
& SS_RESTORE_MASK
);
412 /* This is here 'cause there should be a way of clearing shtraps, but
413 * don't know if this is a sane way of doing it. At the moment,
414 * all users of shtrap are lifetime users (SIGCHLD, SIGALRM, SIGWINCH).
416 if (!(flags
& SS_USER
))
417 p
->shtrap
= (handler_t
) 0;
418 if (flags
& SS_SHTRAP
) {
423 if (p
->cursig
!= f
) {
425 sigemptyset(&sigact
.sa_mask
);
426 sigact
.sa_flags
= KSH_SA_FLAGS
;
427 sigact
.sa_handler
= f
;
428 sigaction(p
->signal
, &sigact
, (struct sigaction
*) 0);
434 /* control what signal is set to before an exec() */
436 setexecsig(p
, restore
)
441 if (!(p
->flags
& (TF_ORIG_IGN
|TF_ORIG_DFL
)))
442 internal_errorf(1, "setexecsig: unset signal %d(%s)",
445 /* restore original value for exec'd kids */
446 p
->flags
&= ~(TF_EXEC_IGN
|TF_EXEC_DFL
);
447 switch (restore
& SS_RESTORE_MASK
) {
448 case SS_RESTORE_CURR
: /* leave things as they currently are */
450 case SS_RESTORE_ORIG
:
451 p
->flags
|= p
->flags
& TF_ORIG_IGN
? TF_EXEC_IGN
: TF_EXEC_DFL
;
454 p
->flags
|= TF_EXEC_DFL
;
457 p
->flags
|= TF_EXEC_IGN
;