Xsession.src: setup proper cpp_* defines for linux
[oweals/cde.git] / cde / programs / dtlogin / server.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*                                                                      *
24  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
25  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
26  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
27  * (c) Copyright 1993, 1994 Novell, Inc.                                *
28  */
29 /*
30  * xdm - display manager daemon
31  *
32  * $XConsortium: server.c /main/4 1995/10/27 16:14:56 rswiston $
33  *
34  * Copyright 1988 Massachusetts Institute of Technology
35  *
36  * Permission to use, copy, modify, and distribute this software and its
37  * documentation for any purpose and without fee is hereby granted, provided
38  * that the above copyright notice appear in all copies and that both that
39  * copyright notice and this permission notice appear in supporting
40  * documentation, and that the name of M.I.T. not be used in advertising or
41  * publicity pertaining to distribution of the software without specific,
42  * written prior permission.  M.I.T. makes no representations about the
43  * suitability of this software for any purpose.  It is provided "as is"
44  * without express or implied warranty.
45  *
46  * Author:  Keith Packard, MIT X Consortium
47  */
48
49 # include       <sys/signal.h>
50 # include       <setjmp.h>
51 # include       <pwd.h>
52 # include       "dm.h"
53 # include       "vgmsg.h"
54
55 static receivedUsr1;
56
57
58
59 /***************************************************************************
60  *
61  *  Local procedure declarations
62  *
63  ***************************************************************************/
64
65 static char * _SysErrorMsg( int n) ;
66 static SIGVAL CatchUsr1( int arg ) ;
67 static void   GetRemoteAddress( struct display *d, int fd) ;
68 static SIGVAL PingBlocked( int arg ) ;
69 static SIGVAL PingLost( int arg ) ;
70 static SIGVAL abortOpen( int arg ) ;
71 static int    serverPause( unsigned t, int serverPid) ;
72 static SIGVAL serverPauseAbort( int arg ) ;
73 static SIGVAL serverPauseUsr1( int arg ) ;
74
75
76
77
78
79 /***************************************************************************
80  *
81  *  Global variables
82  *
83  ***************************************************************************/
84
85 static Display  *dpy;
86
87
88
89 static SIGVAL
90 CatchUsr1( int arg )
91 {
92 #if defined(SYSV) || defined(SVR4)
93     (void) signal (SIGUSR1, CatchUsr1);
94 #endif
95     Debug ("Display Manager caught SIGUSR1\n");
96     ++receivedUsr1;
97 }
98
99 static char * 
100 _SysErrorMsg( int n )
101 {
102
103     char *s = ((n >= 0 && n < sys_nerr) ? sys_errlist[n] : "unknown error");
104
105     return (s ? s : "no such error");
106 }
107
108 int 
109 StartServerOnce( struct display *d )
110 {
111     char        **f;
112     char        **argv;
113     char        arg[1024];
114     int         pid;
115     char        **env;
116     
117     extern struct passwd   puser;       /* pseudo_user password entry   */
118
119     Debug ("Starting server for %s\n", d->name);
120     receivedUsr1 = 0;
121     signal (SIGUSR1, CatchUsr1);
122     argv = d->argv;
123     switch (pid = fork ()) {
124     case 0:
125         CleanUpChild ();
126         if (d->authFile) {
127             sprintf (arg, "-auth %s", d->authFile);
128             argv = parseArgs (argv, arg);
129         }
130         if (!argv) {
131             LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_ARGS,MC_DEF_LOG_NO_ARGS));
132             exit(1);
133         }
134         Debug("Server invoked as ");
135         for (f = argv; *f; f++)
136             Debug ("'%s' ", *f);
137         Debug ("\n");
138
139         /*
140          *  set the permissions on  console devices to  pseudo-user.
141          *  run the server as a pseudo-user, not root...
142          */
143 #ifdef sun
144         if (solaris_setdevperm(d->gettyLine, puser.pw_uid, puser.pw_gid) == 0)
145              Debug ("Unable to set permissions on console devices ..\n");
146         else {
147 #endif
148              setgid (puser.pw_gid);
149              setuid (puser.pw_uid);
150 #ifdef sun
151         }
152 #endif
153
154         /*
155          *  build the server environment (if any)...
156          */
157         env = 0;
158         if (d->environStr && strlen(d->environStr) > 0)
159             env = parseEnv(env, d->environStr);
160 #ifdef sun
161         if (getEnv (env, "OPENWINHOME") == NULL) 
162             env = setEnv(env, "OPENWINHOME", "/usr/openwin");
163 #endif
164 #ifdef _AIX
165         if (getEnv (env, "ODMDIR") == NULL)
166             env = setEnv(env, "ODMDIR", "/etc/objrepos");
167 #ifdef _POWER
168         env = setEnv(env, "XTOEXEC", "true");           /* flag for xserverrc */
169 #endif
170 #endif
171
172         /*
173          * give the server SIGUSR1 ignored,
174          * it will notice that and send SIGUSR1
175          * when ready
176          */
177         signal (SIGUSR1, SIG_IGN);
178         (void) execve (argv[0], argv, env);
179         LogError(ReadCatalog(
180                 MC_LOG_SET,MC_LOG_NO_EXESRV,MC_DEF_LOG_NO_EXESRV),argv[0]);
181         exit(1);
182     case -1:
183         LogError(ReadCatalog(MC_LOG_SET,MC_LOG_FAIL_FORK,MC_DEF_LOG_FAIL_FORK));
184         return 0;
185     default:
186         break;
187     }
188     Debug ("Server started. Process ID = %d\n", pid);
189     d->serverPid = pid;
190     if (serverPause ((unsigned) d->openDelay, pid))
191         return FALSE;
192     return TRUE;
193 }
194
195
196 int 
197 StartServer( struct display *d )
198 {
199     int i;
200     int ret = FALSE;
201
202     i = 0;
203     while (d->serverAttempts == 0 || i < d->serverAttempts)
204     {
205         if ((ret = StartServerOnce (d)) == TRUE)
206             break;
207         sleep (d->openDelay);
208         i++;
209     }
210     return ret;
211 }
212
213
214 /*
215  * sleep for t seconds, return 1 if the server is dead when
216  * the sleep finishes, 0 else
217  */
218
219 static jmp_buf  pauseAbort;
220 static int      serverPauseRet;
221
222 static SIGVAL
223 serverPauseAbort( int arg )
224 {
225     Debug ("Display Manager pause timed out\n");
226     longjmp (pauseAbort, 1);
227 }
228
229 static SIGVAL
230 serverPauseUsr1( int arg )
231 {
232     Debug ("Display Manager pause received SIGUSR1\n");
233     ++receivedUsr1;
234     longjmp (pauseAbort, 1);
235 }
236
237 static int 
238 serverPause( unsigned t, int serverPid )
239 {
240     int         pid;
241
242     serverPauseRet = 0;
243     Debug ("Display Manager pausing until SIGUSR1 from server or timeout\n");
244     if (!setjmp (pauseAbort)) {
245         signal (SIGALRM, serverPauseAbort);
246         signal (SIGUSR1, serverPauseUsr1);
247 #ifdef SYSV
248         if (receivedUsr1)
249             alarm ((unsigned) 1);
250         else
251             alarm (t);
252 #else
253         if (!receivedUsr1)
254             alarm (t);
255         else
256             Debug ("ServerPause(): already received USR1\n");
257 #endif
258         for (;;) {
259 #ifdef SYSV
260             pid = wait ((waitType *) 0);
261 #else
262             if (!receivedUsr1)
263                 pid = wait ((waitType *) 0);
264             else
265 #  ifdef        SVR4
266                 {
267                     int dummy;
268                 pid = waitpid ((pid_t) 0,&dummy,WNOHANG);
269                 }
270 #  else
271                 pid = wait3 ((waitType *) 0, WNOHANG,
272                              (struct rusage *) 0);
273 #  endif
274 #endif
275             if (pid == serverPid ||
276                 pid == -1 && errno == ECHILD)
277             {
278                 Debug ("Server dead\n");
279                 serverPauseRet = 1;
280                 break;
281             }
282 #ifndef SYSV
283             if (pid == 0) {
284                 Debug ("Server alive and kicking\n");
285                 break;
286             }
287 #endif
288         }
289     }
290     alarm ((unsigned) 0);
291     signal (SIGALRM, SIG_DFL);
292     signal (SIGUSR1, CatchUsr1);
293     if (serverPauseRet) {
294         Debug ("Server died\n");
295         LogError(ReadCatalog(MC_LOG_SET,MC_LOG_SRV_DIED,MC_DEF_LOG_SRV_DIED));
296     }
297     return serverPauseRet;
298 }
299
300
301 /*
302  * this code is complicated by some TCP failings.  On
303  * many systems, the connect will occasionally hang forever,
304  * this trouble is avoided by setting up a timeout to longjmp
305  * out of the connect (possibly leaving piles of garbage around
306  * inside Xlib) and give up, terminating the server.
307  */
308
309 static jmp_buf  openAbort;
310
311 static SIGVAL
312 abortOpen( int arg )
313 {
314         longjmp (openAbort, 1);
315 }
316
317 static void
318 GetRemoteAddress( struct display *d, int fd )
319 {
320     char    buf[512];
321     int     len = sizeof (buf);
322
323     if (d->peer)
324         free ((char *) d->peer);
325     getpeername (fd, (struct sockaddr *) buf, &len);
326     d->peerlen = 0;
327     if (len)
328     {
329         d->peer = (struct sockaddr *) malloc (len);
330         if (d->peer)
331         {
332             bcopy (buf, (char *) d->peer, len);
333             d->peerlen = len;
334         }
335     }
336     Debug ("Got remote address %s %d\n", d->name, d->peerlen);
337 }
338
339
340
341 /****************************************************************************
342  *
343  *  LogOpenError()
344  *
345  *  If d->startAttempts is a large number and a connection cannot be made to
346  *  the server, the error log can fill up rapidly with error messages. This
347  *  could be common in X-terminals that do not support XDMCP and are turned
348  *  off over a weekend. This routine attempts to reduce the number of error
349  *  messages logged in this scenario.
350  *  
351  ****************************************************************************/
352
353 int 
354 LogOpenError( int count )
355 {
356
357     if ( count <= 10                        ) return 1;
358     if ( count <= 100 && (count %  10 == 0) ) return 1;
359     if ( count <= 500 && (count %  50 == 0) ) return 1;
360     if (                 (count % 100 == 0) ) return 1;
361     
362     return 0;
363 }
364
365
366 int 
367 WaitForServer( struct display *d )
368 {
369     int     i;
370
371     for (i = 0; i < (d->openRepeat > 0 ? d->openRepeat : 1); i++) {
372         (void) signal (SIGALRM, abortOpen);
373         (void) alarm ((unsigned) d->openTimeout);
374         if (!setjmp (openAbort)) {
375             Debug ("Before XOpenDisplay(%s)\n", d->name);
376             errno = 0;
377             dpy = XOpenDisplay (d->name);
378             (void) alarm ((unsigned) 0);
379             (void) signal (SIGALRM, SIG_DFL);
380             Debug ("After XOpenDisplay()\n");
381             if (dpy) {
382                 if (d->displayType.location == Foreign)
383                     GetRemoteAddress (d, ConnectionNumber (dpy));
384                 RegisterCloseOnFork (ConnectionNumber (dpy));
385                 (void) fcntl (ConnectionNumber (dpy), F_SETFD, 0);
386                 return 1;
387             } else {
388                 Debug ("OpenDisplay failed %d (%s)\n",
389                        errno, _SysErrorMsg (errno));
390             }
391             Debug ("Waiting for server to start %d\n", i);
392             sleep ((unsigned) d->openDelay);
393         } else {
394             Debug ("Hung in open, aborting\n");
395             if (LogOpenError(d->startTries))
396                 LogError(ReadCatalog(
397                         MC_LOG_SET,MC_LOG_HUNG_DPY,MC_DEF_LOG_HUNG_DPY),
398                            d->name, d->startTries);
399             (void) signal (SIGALRM, SIG_DFL);
400             break;
401         }
402     }
403     Debug ("Giving up on server\n");
404     if (LogOpenError(d->startTries))
405         LogError(ReadCatalog(
406                 MC_LOG_SET,MC_LOG_FAIL_SRVOPEN,MC_DEF_LOG_FAIL_SRVOPEN),
407                 d->startTries, d->name);
408     return 0;
409 }
410
411 void
412 ResetServer( struct display *d )
413 {
414     if (dpy && d->displayType.origin != FromXDMCP)
415         pseudoReset (dpy);
416 }
417
418
419 /****************************************************************************
420  *
421  *  Server pinging routines...
422  *
423  *  These routines attempt to determine if the server is still alive.
424  *  Periodically (d->pingInterval) an XSync is sent to the server. If an I/O
425  *  error occurs, then the connection has been lost and the server needs to
426  *  be reset. If the server is blocked for some reason (i.e. server grab) the
427  *  XSync will block until a local timer expires. In this case, we just note
428  *  the block and continue...
429  *
430  *  7/26/90 - prr
431  *  The XSync was replaced by a socket-level ping. For some reason, an XSync
432  *  to a grabbed server causes a subsequent pseudoReset (KillClients) to not 
433  *  kill all clients. The socket ping is not affected by a grabbed server,
434  *  but it cannot detect a server shutdown and restart within one ping
435  *  interval. 
436  *
437  ****************************************************************************/
438
439 static jmp_buf  pingTime;
440 static int      serverDead = FALSE;
441
442 static SIGVAL
443 PingLost( int arg )
444 {
445     serverDead = TRUE;
446     longjmp (pingTime, 1);
447 }
448
449
450 static SIGVAL
451 PingBlocked( int arg )
452 {
453     serverDead = FALSE;
454     longjmp (pingTime, 1);
455 }
456
457
458 int 
459 PingServer( struct display *d, Display *alternateDpy )
460 {
461     int     (*oldError)();
462     SIGVAL  (*oldSig)();
463     int     oldAlarm;
464
465     if (!alternateDpy)
466         alternateDpy = dpy;
467     oldError = XSetIOErrorHandler ((XIOErrorHandler)PingLost);
468     oldAlarm = alarm (0);
469     oldSig = signal (SIGALRM, PingBlocked);
470     alarm (d->pingTimeout * 60);
471     if (!setjmp (pingTime))
472     {
473         Debug ("Ping server\n");
474         XNoOp (alternateDpy);
475         XSync (alternateDpy, 0);
476         Debug ("Server alive\n");
477
478         while (XPending(alternateDpy)) {
479             XEvent event;
480             XNextEvent(alternateDpy, &event);
481         }
482     }
483     else
484     {
485         if ( serverDead ) {
486             Debug ("Server dead\n");
487             alarm (0);
488             signal (SIGALRM, SIG_DFL);
489             XSetIOErrorHandler (oldError);
490             return 0;
491         }
492         else
493             Debug ("Server blocked, continuing...\n");
494     }
495     alarm (0);
496     signal (SIGALRM, oldSig);
497     alarm (oldAlarm);
498     XSetIOErrorHandler (oldError);
499     return 1;
500 }