7 /* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */
11 /* Table is indexed by signal number
13 * The script siglist.sh generates siglist.out, which is a sorted, complete
16 Trap sigtraps
[SIGNALS
+1] = {
17 { SIGEXIT_
, "EXIT", "Signal 0", 0, 0, 0, 0, 0 },
18 #include "siglist.out" /* generated by siglist.sh */
21 static struct sigaction Sigact_ign
, Sigact_trap
;
26 #ifdef HAVE_SYS_SIGLIST
27 # ifndef SYS_SIGLIST_DECLARED
28 extern char *sys_siglist
[];
32 /* Use system description, if available, for unknown signals... */
33 for (i
= 0; i
< NSIG
; i
++)
34 if (!sigtraps
[i
].name
&& sys_siglist
[i
] && sys_siglist
[i
][0])
35 sigtraps
[i
].mess
= sys_siglist
[i
];
36 #endif /* HAVE_SYS_SIGLIST */
38 sigemptyset(&Sigact_ign
.sa_mask
);
39 Sigact_ign
.sa_flags
= KSH_SA_FLAGS
;
40 Sigact_ign
.sa_handler
= SIG_IGN
;
41 Sigact_trap
= Sigact_ign
;
42 Sigact_trap
.sa_handler
= trapsig
;
44 sigtraps
[SIGINT
].flags
|= TF_DFL_INTR
| TF_TTY_INTR
;
45 sigtraps
[SIGQUIT
].flags
|= TF_DFL_INTR
| TF_TTY_INTR
;
46 sigtraps
[SIGTERM
].flags
|= TF_DFL_INTR
;/* not fatal for interactive */
47 sigtraps
[SIGHUP
].flags
|= TF_FATAL
;
48 sigtraps
[SIGCHLD
].flags
|= TF_SHELL_USES
;
50 /* these are always caught so we can clean up any temproary files. */
51 setsig(&sigtraps
[SIGINT
], trapsig
, SS_RESTORE_ORIG
);
52 setsig(&sigtraps
[SIGQUIT
], trapsig
, SS_RESTORE_ORIG
);
53 setsig(&sigtraps
[SIGTERM
], trapsig
, SS_RESTORE_ORIG
);
54 setsig(&sigtraps
[SIGHUP
], trapsig
, SS_RESTORE_ORIG
);
58 static RETSIGTYPE alarm_catcher
ARGS((int sig
));
63 sigtraps
[SIGALRM
].flags
|= TF_SHELL_USES
;
64 setsig(&sigtraps
[SIGALRM
], alarm_catcher
,
65 SS_RESTORE_ORIG
|SS_FORCE
|SS_SHTRAP
);
72 if (ksh_tmout_state
== TMOUT_READING
) {
76 ksh_tmout_state
= TMOUT_LEAVING
;
86 gettrap(const char *name
)
94 if (getn(name
, &n
) && ((0 == n
) || (1 == n
) || (2 == n
) || (3 == n
) || (6 == n
) || (9 == n
) || (13 == n
) || (14 == n
) || (15 == n
) ))
98 for (p
= sigtraps
, i
= SIGNALS
+1; --i
>= 0; p
++)
99 if (p
->name
&& strcmp(p
->name
, name
) == 0)
105 * trap signal handler
111 Trap
*p
= &sigtraps
[i
];
114 if (p
->flags
& TF_DFL_INTR
)
116 if ((p
->flags
& TF_FATAL
) && !p
->trap
) {
123 if (sigtraps
[i
].cursig
== trapsig
) /* this for SIGCHLD,SIGALRM */
124 sigaction(i
, &Sigact_trap
, (struct sigaction
*) 0);
125 #endif /* V7_SIGNALS */
129 /* called when we want to allow the user to ^C out of something - won't
130 * work if user has trapped SIGINT.
136 runtraps(TF_DFL_INTR
|TF_FATAL
);
139 /* called after EINTR to check if a signal with normally causes process
140 * termination has been received.
148 /* todo: should check if signal is fatal, not the TF_DFL_INTR flag */
149 for (p
= sigtraps
, i
= SIGNALS
+1; --i
>= 0; p
++)
150 if (p
->set
&& (p
->flags
& (TF_DFL_INTR
|TF_FATAL
)))
151 /* return value is used as an exit code */
152 return 128 + p
->signal
;
156 /* Returns the signal number of any pending traps: ie, a signal which has
157 * occured for which a trap has been set or for which the TF_DFL_INTR flag
166 for (p
= sigtraps
, i
= SIGNALS
+1; --i
>= 0; p
++)
167 if (p
->set
&& ((p
->trap
&& p
->trap
[0])
168 || ((p
->flags
& (TF_DFL_INTR
|TF_FATAL
))
175 * run any pending traps. If intr is set, only run traps that
176 * can interrupt commands.
186 if (ksh_tmout_state
== TMOUT_LEAVING
) {
187 ksh_tmout_state
= TMOUT_EXECUTING
;
188 warningf(FALSE
, "timed out waiting for input");
191 /* XXX: this means the alarm will have no effect if a trap
192 * is caught after the alarm() was started...not good.
194 ksh_tmout_state
= TMOUT_EXECUTING
;
198 if (flag
& TF_DFL_INTR
)
202 for (p
= sigtraps
, i
= SIGNALS
+1; --i
>= 0; p
++)
204 || ((p
->flags
& flag
) && p
->trap
== (char *) 0)))
213 char *trapstr
= p
->trap
;
215 int UNINITIALIZED(old_changed
);
218 if (trapstr
== (char *) 0) { /* SIG_DFL */
219 if (p
->flags
& TF_FATAL
) {
224 if (p
->flags
& TF_DFL_INTR
) {
225 /* eg, SIGINT, SIGQUIT, SIGTERM, etc. */
231 if (trapstr
[0] == '\0') /* SIG_IGN */
233 if (i
== SIGEXIT_
) { /* avoid recursion on these */
234 old_changed
= p
->flags
& TF_CHANGED
;
235 p
->flags
&= ~TF_CHANGED
;
236 p
->trap
= (char *) 0;
239 /* Note: trapstr is fully parsed before anything is executed, thus
240 * no problem with afree(p->trap) in settrap() while still in use.
244 if (i
== SIGEXIT_
) {
245 if (p
->flags
& TF_CHANGED
)
246 /* don't clear TF_CHANGED */
247 afree(trapstr
, APERM
);
250 p
->flags
|= old_changed
;
254 /* clear pending traps and reset user's trap handlers; used after fork(2) */
264 for (i
= SIGNALS
+1, p
= sigtraps
; --i
>= 0; p
++) {
266 if ((p
->flags
& TF_USER_SET
) && (p
->trap
&& p
->trap
[0]))
267 settrap(p
, (char *) 0);
271 /* restore signals just before an exec(2) */
278 for (i
= SIGNALS
+1, p
= sigtraps
; --i
>= 0; p
++)
279 if (p
->flags
& (TF_EXEC_IGN
|TF_EXEC_DFL
))
280 setsig(p
, (p
->flags
& TF_EXEC_IGN
) ? SIG_IGN
: SIG_DFL
,
281 SS_RESTORE_CURR
|SS_FORCE
);
292 afree(p
->trap
, APERM
);
293 p
->trap
= str_save(s
, APERM
); /* handles s == 0 */
294 p
->flags
|= TF_CHANGED
;
295 f
= !s
? SIG_DFL
: s
[0] ? trapsig
: SIG_IGN
;
297 p
->flags
|= TF_USER_SET
;
298 if ((p
->flags
& (TF_DFL_INTR
|TF_FATAL
)) && f
== SIG_DFL
)
300 else if (p
->flags
& TF_SHELL_USES
) {
301 if (!(p
->flags
& TF_ORIG_IGN
) || Flag(FTALKING
)) {
302 /* do what user wants at exec time */
303 p
->flags
&= ~(TF_EXEC_IGN
|TF_EXEC_DFL
);
305 p
->flags
|= TF_EXEC_IGN
;
307 p
->flags
|= TF_EXEC_DFL
;
309 /* assumes handler already set to what shell wants it
310 * (normally trapsig, but could be j_sigchld() or SIG_IGN)
315 /* todo: should we let user know signal is ignored? how? */
316 setsig(p
, f
, SS_RESTORE_CURR
|SS_USER
);
319 /* Called by c_print() when writing to a co-process to ensure SIGPIPE won't
320 * kill shell (unless user catches it and exits)
326 Trap
*p
= &sigtraps
[SIGPIPE
];
328 if (!(p
->flags
& (TF_ORIG_IGN
|TF_ORIG_DFL
))) {
329 setsig(p
, SIG_IGN
, SS_RESTORE_CURR
);
330 if (p
->flags
& TF_ORIG_DFL
)
332 } else if (p
->cursig
== SIG_DFL
) {
333 setsig(p
, SIG_IGN
, SS_RESTORE_CURR
);
334 restore_dfl
= 1; /* restore to SIG_DFL */
339 /* Called by c_print() to undo whatever block_pipe() did */
341 restore_pipe(restore_dfl
)
345 setsig(&sigtraps
[SIGPIPE
], SIG_DFL
, SS_RESTORE_CURR
);
348 /* Set action for a signal. Action may not be set if original
349 * action was SIG_IGN, depending on the value of flags and
358 struct sigaction sigact
;
360 if (p
->signal
== SIGEXIT_
)
363 /* First time setting this signal? If so, get and note the current
366 if (!(p
->flags
& (TF_ORIG_IGN
|TF_ORIG_DFL
))) {
367 sigaction(p
->signal
, &Sigact_ign
, &sigact
);
368 p
->flags
|= sigact
.sa_handler
== SIG_IGN
?
369 TF_ORIG_IGN
: TF_ORIG_DFL
;
373 /* Generally, an ignored signal stays ignored, except if
374 * - the user of an interactive shell wants to change it
375 * - the shell wants for force a change
377 if ((p
->flags
& TF_ORIG_IGN
) && !(flags
& SS_FORCE
)
378 && (!(flags
& SS_USER
) || !Flag(FTALKING
)))
381 setexecsig(p
, flags
& SS_RESTORE_MASK
);
383 /* This is here 'cause there should be a way of clearing shtraps, but
384 * don't know if this is a sane way of doing it. At the moment,
385 * all users of shtrap are lifetime users (SIGCHLD, SIGALRM, SIGWINCH).
387 if (!(flags
& SS_USER
))
388 p
->shtrap
= (handler_t
) 0;
389 if (flags
& SS_SHTRAP
) {
394 if (p
->cursig
!= f
) {
396 sigemptyset(&sigact
.sa_mask
);
397 sigact
.sa_flags
= KSH_SA_FLAGS
;
398 sigact
.sa_handler
= f
;
399 sigaction(p
->signal
, &sigact
, (struct sigaction
*) 0);
405 /* control what signal is set to before an exec() */
407 setexecsig(p
, restore
)
412 if (!(p
->flags
& (TF_ORIG_IGN
|TF_ORIG_DFL
)))
413 internal_errorf(1, "setexecsig: unset signal %d(%s)",
416 /* restore original value for exec'd kids */
417 p
->flags
&= ~(TF_EXEC_IGN
|TF_EXEC_DFL
);
418 switch (restore
& SS_RESTORE_MASK
) {
419 case SS_RESTORE_CURR
: /* leave things as they currently are */
421 case SS_RESTORE_ORIG
:
422 p
->flags
|= p
->flags
& TF_ORIG_IGN
? TF_EXEC_IGN
: TF_EXEC_DFL
;
425 p
->flags
|= TF_EXEC_DFL
;
428 p
->flags
|= TF_EXEC_IGN
;