5 /* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */
9 Trap sigtraps
[NSIG
+1] = {
10 { SIGEXIT_
, "EXIT", "Signal 0" },
12 { SIGERR_
, "ERR", "Error handler" },
15 static struct sigaction Sigact_ign
, Sigact_trap
;
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
);
44 sigtraps
[SIGALRM
].flags
|= TF_SHELL_USES
;
45 setsig(&sigtraps
[SIGALRM
], alarm_catcher
,
46 SS_RESTORE_ORIG
|SS_FORCE
|SS_SHTRAP
);
50 alarm_catcher(int sig
)
54 if (ksh_tmout_state
== TMOUT_READING
) {
58 ksh_tmout_state
= TMOUT_LEAVING
;
68 gettrap(const char *name
, int igncase
)
76 if (getn(name
, &n
) && 0 <= n
&& n
< NSIG
)
80 for (p
= sigtraps
, i
= NSIG
+1; --i
>= 0; p
++)
83 if (p
->name
&& (!strcasecmp(p
->name
, name
) ||
84 (strlen(name
) > 3 && !strncasecmp("SIG",
86 !strcasecmp(p
->name
, name
+ 3))))
89 if (p
->name
&& (!strcmp(p
->name
, name
) ||
90 (strlen(name
) > 3 && !strncmp("SIG",
91 p
->name
, 3) && !strcmp(p
->name
, name
+ 3))))
104 Trap
*p
= &sigtraps
[i
];
108 if (p
->flags
& TF_DFL_INTR
)
110 if ((p
->flags
& TF_FATAL
) && !p
->trap
) {
117 if (sigtraps
[i
].cursig
== trapsig
) /* this for SIGCHLD,SIGALRM */
118 sigaction(i
, &Sigact_trap
, (struct sigaction
*) 0);
122 /* called when we want to allow the user to ^C out of something - won't
123 * work if user has trapped SIGINT.
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)
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
;
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
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
)))
167 * run any pending traps. If intr is set, only run traps that
168 * can interrupt commands.
176 if (ksh_tmout_state
== TMOUT_LEAVING
) {
177 ksh_tmout_state
= TMOUT_EXECUTING
;
178 warningf(false, "timed out waiting for input");
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
;
187 if (flag
& TF_DFL_INTR
)
191 for (p
= sigtraps
, i
= NSIG
+1; --i
>= 0; p
++)
192 if (p
->set
&& (!flag
||
193 ((p
->flags
& flag
) && p
->trap
== (char *) 0)))
201 char *trapstr
= p
->trap
;
206 if (trapstr
== (char *) 0) { /* SIG_DFL */
207 if (p
->flags
& TF_FATAL
) {
212 if (p
->flags
& TF_DFL_INTR
) {
213 /* eg, SIGINT, SIGQUIT, SIGTERM, etc. */
219 if (trapstr
[0] == '\0') /* SIG_IGN */
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;
227 /* Note: trapstr is fully parsed before anything is executed, thus
228 * no problem with afree(p->trap) in settrap() while still in use.
232 if (i
== SIGEXIT_
|| i
== SIGERR_
) {
233 if (p
->flags
& TF_CHANGED
)
234 /* don't clear TF_CHANGED */
235 afree(trapstr
, APERM
);
238 p
->flags
|= old_changed
;
242 /* clear pending traps and reset user's trap handlers; used after fork(2) */
252 for (i
= NSIG
+1, p
= sigtraps
; --i
>= 0; p
++) {
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) */
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
);
273 settrap(Trap
*p
, char *s
)
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
)
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
);
291 p
->flags
|= TF_EXEC_IGN
;
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)
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)
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
)
318 } else if (p
->cursig
== SIG_DFL
) {
319 setsig(p
, SIG_IGN
, SS_RESTORE_CURR
);
320 restore_dfl
= 1; /* restore to SIG_DFL */
325 /* Called by c_print() to undo whatever block_pipe() did */
327 restore_pipe(int 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
338 setsig(Trap
*p
, sig_t f
, int flags
)
340 struct sigaction sigact
;
342 if (p
->signal
== SIGEXIT_
|| p
->signal
== SIGERR_
)
345 /* First time setting this signal? If so, get and note the current
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
;
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
)))
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
))
371 if (flags
& SS_SHTRAP
) {
376 if (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);
387 /* control what signal is set to before an exec() */
389 setexecsig(Trap
*p
, int restore
)
392 if (!(p
->flags
& (TF_ORIG_IGN
|TF_ORIG_DFL
)))
393 internal_errorf(1, "setexecsig: unset signal %d(%s)",
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 */
401 case SS_RESTORE_ORIG
:
402 p
->flags
|= p
->flags
& TF_ORIG_IGN
? TF_EXEC_IGN
: TF_EXEC_DFL
;
405 p
->flags
|= TF_EXEC_DFL
;
408 p
->flags
|= TF_EXEC_IGN
;