1/* $Xorg: signals.c,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */
2/******************************************************************************
3
4Copyright 1994, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25******************************************************************************/
26/* $XFree86: xc/programs/xsm/signals.c,v 3.5 2001/12/08 18:33:45 herrb Exp $ */
27
28#include <stdlib.h>
29
30#include <X11/Xos.h>
31#include <X11/Xfuncs.h>
32#include <X11/Intrinsic.h>
33
34#include <X11/SM/SMlib.h>
35
36#include "save.h"
37
38#include <errno.h>
39#include <sys/types.h>
40
41#ifdef X_POSIX_C_SOURCE
42#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
43#include <signal.h>
44#include <sys/wait.h>
45#undef _POSIX_C_SOURCE
46#else
47#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
48#include <signal.h>
49#include <sys/wait.h>
50#else
51#define _POSIX_SOURCE
52#include <signal.h>
53#include <sys/wait.h>
54#undef _POSIX_SOURCE
55#endif
56#endif
57#include "list.h"
58#include "save.h"
59
60#ifndef X_NOT_POSIX
61#define USE_POSIX_WAIT
62#endif
63
64#ifdef linux
65#define USE_SYSV_SIGNALS
66#endif
67
68#include <stddef.h>
69
70#include "xsm.h"
71
72int checkpoint_from_signal = 0;
73
74
75static void
76Signal(int sig, void (*handler)(int))
77{
78#ifndef X_NOT_POSIX
79    struct sigaction sigact, osigact;
80    sigact.sa_handler = handler;
81    sigemptyset(&sigact.sa_mask);
82    sigact.sa_flags = 0;
83    sigaction(sig, &sigact, &osigact);
84#else
85    signal(sig, handler);
86#endif
87}
88
89
90void
91sig_child_handler (int sig)
92
93{
94    int pid, olderrno = errno;
95
96#if !defined(USE_POSIX_WAIT) && defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
97    wait (NULL);
98#endif
99
100    /*
101     * The wait() above must come before re-establishing the signal handler.
102     * In between this time, a new child might have died.  If we can do
103     * a non-blocking wait, we can check for this race condition.  If we
104     * don't have non-blocking wait, we lose.
105     */
106
107    do
108    {
109#ifdef USE_POSIX_WAIT
110	pid = waitpid (-1, NULL, WNOHANG);
111#else
112#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
113	/* cannot do non-blocking wait */
114	pid = 0;
115#else
116	union wait status;
117
118	pid = wait3 (&status, WNOHANG, (struct rusage *)NULL);
119#endif
120#endif /* USE_POSIX_WAIT else */
121    }
122    while (pid > 0);
123    errno = olderrno;
124}
125
126
127void
128sig_term_handler(int sig)
129{
130    XtNoticeSignal(sig_term_id);
131}
132
133void
134xt_sig_term_handler (XtPointer closure, XtSignalId *id)
135
136{
137    wantShutdown = 1;
138    checkpoint_from_signal = 1;
139    DoSave (SmSaveLocal, SmInteractStyleNone, 1 /* fast */);
140}
141
142void sig_usr1_handler(int sig)
143{
144    XtNoticeSignal(sig_usr1_id);
145}
146
147void
148xt_sig_usr1_handler (XtPointer closure, XtSignalId *id)
149
150{
151    wantShutdown = 0;
152    checkpoint_from_signal = 1;
153    DoSave (SmSaveLocal, SmInteractStyleNone, 0 /* fast */);
154}
155
156
157
158void
159register_signals (XtAppContext appContext)
160
161{
162    /*
163     * Ignore SIGPIPE
164     */
165
166    Signal (SIGPIPE, SIG_IGN);
167
168
169    /*
170     * If child process dies, call our handler
171     */
172
173    Signal (SIGCHLD, sig_child_handler);
174
175
176    /*
177     * If we get a SIGTERM, do shutdown, fast, local, no interact
178     */
179
180    Signal (SIGTERM, sig_term_handler);
181    sig_term_id = XtAppAddSignal(appContext, xt_sig_term_handler, NULL);
182
183
184    /*
185     * If we get a SIGUSR1, do checkpoint, local, no interact
186     */
187
188    Signal (SIGUSR1, sig_usr1_handler);
189    sig_usr1_id = XtAppAddSignal(appContext, xt_sig_usr1_handler, NULL);
190}
191
192
193
194int
195execute_system_command (char *s)
196{
197    int stat;
198
199#ifdef X_NOT_POSIX
200    /*
201     * Non-POSIX system() uses wait().  We must disable our sig child
202     * handler because if it catches the signal, system() will block
203     * forever in wait().
204     */
205
206    int pid;
207
208    Signal (SIGCHLD, SIG_IGN);
209#endif
210
211    stat = system (s);
212
213#ifdef X_NOT_POSIX
214    /*
215     * Re-enable our sig child handler.  We might have missed some signals,
216     * so do non-blocking waits until there are no signals left.
217     */
218
219    Signal (SIGCHLD, sig_child_handler);
220
221#if !(defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP))
222    do
223    {
224	union wait status;
225
226	pid = wait3 (&status, WNOHANG, (struct rusage *)NULL);
227    } while (pid > 0);
228#endif
229#endif   /* X_NOT_POSIX */
230
231    return (stat);
232}
233
234
235