2 /***************************************************************************
4 ****************************************************************************
5 * ncurses is copyright (C) 1992-1995 *
7 * zmbenhal@netcom.com *
9 * esr@snark.thyrsus.com *
11 * Permission is hereby granted to reproduce and distribute ncurses *
12 * by any means and for any fee, whether alone or as part of a *
13 * larger distribution, in source or in binary form, PROVIDED *
14 * this notice is included with any such distribution, and is not *
15 * removed from any of its header files. Mention of ncurses in any *
16 * applications linked with it is highly appreciated. *
18 * ncurses comes AS IS with no warranty, implied or expressed. *
20 ***************************************************************************/
26 ** The routine _nc_signal_handler().
30 #include <curses.priv.h>
35 #if !HAVE_TYPE_SIGACTION
36 typedef struct sigaction sigaction_t;
38 #else /* !HAVE_SIGACTION */
40 #include <SigAction.h>
48 MODULE_ID("$Id: lib_tstp.c,v 1.8 1996/11/17 00:11:41 tom Exp $")
51 * Note: This code is fragile! Its problem is that different OSs
52 * handle restart of system calls interrupted by signals differently.
53 * The ncurses code needs signal-call restart to happen -- otherwise,
54 * interrupted wgetch() calls will return FAIL, probably making the
55 * application think the input stream has ended and it should
56 * terminate. In particular, you know you have this problem if, when
57 * you suspend an ncurses-using lynx with ^Z and resume, it dies
60 * Default behavior of POSIX sigaction(2) is not to restart
61 * interrupted system calls, but Linux's sigaction does it anyway (at
62 * least, on and after the 1.1.47 I (esr) use). Thus this code works
63 * OK under Linux. The 4.4BSD sigaction(2) supports a (non-portable)
64 * SA_RESTART flag that forces the right behavior. Thus, this code
65 * should work OK under BSD/OS, NetBSD, and FreeBSD (let us know if it
68 * Stock System Vs (and anything else using a strict-POSIX
69 * sigaction(2) without SA_RESTART) may have a problem. Possible
72 * sigvec restarts by default (SV_INTERRUPT flag to not restart)
73 * signal restarts by default in SVr4 (assuming you link with -lucb)
74 * and BSD, but not SVr3.
75 * sigset restarts, but is only available under SVr4/Solaris.
77 * The signal(3) call is mandated by the ANSI standard, and its
78 * interaction with sigaction(2) is described in the POSIX standard
79 * (3.3.4.2, page 72,line 934). According to section 8.1, page 191,
80 * however, signal(3) itself is not required by POSIX.1. And POSIX is
81 * silent on whether it is required to restart signals.
83 * So. The present situation is, we use sigaction(2) with no
84 * guarantee of restart anywhere but on Linux and BSD. We could
85 * switch to signal(3) and collar Linux, BSD, and SVr4. Any way
86 * we slice it, System V UNIXes older than SVr4 will probably lose
87 * (this may include XENIX).
89 * This implementation will probably be changed to use signal(3) in
90 * the future. If nothing else, it's simpler...
94 static void tstp(int dummy GCC_UNUSED)
97 sigaction_t act, oact;
102 * The user may have changed the prog_mode tty bits, so save them.
107 * Block window change and timer signals. The latter
108 * is because applications use timers to decide when
109 * to repaint the screen.
111 (void)sigemptyset(&mask);
112 (void)sigaddset(&mask, SIGALRM);
114 (void)sigaddset(&mask, SIGWINCH);
116 (void)sigprocmask(SIG_BLOCK, &mask, &omask);
119 * End window mode, which also resets the terminal state to the
120 * original (pre-curses) modes.
124 /* Unblock SIGTSTP. */
125 (void)sigemptyset(&mask);
126 (void)sigaddset(&mask, SIGTSTP);
127 (void)sigprocmask(SIG_UNBLOCK, &mask, NULL);
129 /* Now we want to resend SIGSTP to this process and suspend it */
130 act.sa_handler = SIG_DFL;
131 sigemptyset(&act.sa_mask);
134 act.sa_flags |= SA_RESTART;
135 #endif /* SA_RESTART */
136 sigaction(SIGTSTP, &act, &oact);
137 kill(getpid(), SIGTSTP);
139 /* Process gets suspended...time passes...process resumes */
141 T(("SIGCONT received"));
142 sigaction(SIGTSTP, &oact, NULL);
146 * If the user modified the tty state while suspended, he wants
147 * those changes to stick. So save the new "default" terminal state.
152 * This relies on the fact that doupdate() will restore the
153 * program-mode tty state, and issue enter_ca_mode if need be.
157 /* Reset the signals. */
158 (void)sigprocmask(SIG_SETMASK, &omask, NULL);
160 #endif /* defined(SIGTSTP) */
162 static void cleanup(int sig)
165 * Actually, doing any sort of I/O from within an signal handler is
166 * "unsafe". But we'll _try_ to clean up the screen and terminal
167 * settings on the way out.
171 #if HAVE_SIGACTION || HAVE_SIGVEC
173 sigemptyset(&act.sa_mask);
175 act.sa_handler = SIG_IGN;
176 if (sigaction(sig, &act, (sigaction_t *)0) == 0) {
180 if (signal(sig, SIG_IGN) != SIG_ERR) {
189 * If the given signal is still in its default state, set it to the given
192 #if HAVE_SIGACTION || HAVE_SIGVEC
193 static int CatchIfDefault(int sig, sigaction_t *act)
198 act->sa_flags |= SA_RESTART;
199 #endif /* SA_RESTART */
200 if (sigaction(sig, (sigaction_t *)0, &old_act) == 0
201 && old_act.sa_handler == SIG_DFL) {
202 (void)sigaction(sig, act, (sigaction_t *)0);
208 static int CatchIfDefault(int sig, RETSIGTYPE (*handler)())
212 ohandler = signal(sig, SIG_IGN);
213 if (ohandler == SIG_DFL) {
214 signal(sig, handler);
217 signal(sig, ohandler);
224 * This is invoked once at the beginning (e.g., from 'initscr()'), to
225 * initialize the signal catchers, and thereafter when spawning a shell (and
226 * returning) to disable/enable the SIGTSTP (i.e., ^Z) catcher.
228 * If the application has already set one of the signals, we'll not modify it
229 * (during initialization).
231 * The XSI document implies that we shouldn't keep the SIGTSTP handler if
232 * the caller later changes its mind, but that doesn't seem correct.
234 void _nc_signal_handler(bool enable)
236 #ifdef SIGTSTP /* Xenix 2.x doesn't have this */
237 static sigaction_t act, oact;
244 act.sa_handler = SIG_IGN;
245 sigaction(SIGTSTP, &act, &oact);
247 else if (act.sa_handler)
249 sigaction(SIGTSTP, &oact, NULL);
253 sigemptyset(&act.sa_mask);
256 act.sa_flags |= SA_RESTART;
257 #endif /* SA_RESTART */
259 act.sa_handler = cleanup;
260 CatchIfDefault(SIGINT, &act);
261 CatchIfDefault(SIGTERM, &act);
263 act.sa_handler = tstp;
264 if (!CatchIfDefault(SIGTSTP, &act))
271 #if HAVE_SIGACTION || HAVE_SIGVEC
272 static sigaction_t act;
273 act.sa_handler = cleanup;
274 CatchIfDefault(SIGINT, &act);
275 CatchIfDefault(SIGTERM, &act);
277 CatchIfDefault(SIGINT, cleanup);
278 CatchIfDefault(SIGTERM, cleanup);