Linux has the same value for ENOTSUP as another var, therefore protect one
[oweals/cde.git] / cde / programs / dtlogin / dm.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 /* (c) Copyright 1997 The Open Group */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30 /*
31  * xdm - display manager daemon
32  *
33  * $TOG: dm.c /main/18 1999/01/19 17:44:08 mgreess $
34  *
35  * Copyright 1988 Massachusetts Institute of Technology
36  *
37  * Permission to use, copy, modify, and distribute this software and its
38  * documentation for any purpose and without fee is hereby granted, provided
39  * that the above copyright notice appear in all copies and that both that
40  * copyright notice and this permission notice appear in supporting
41  * documentation, and that the name of M.I.T. not be used in advertising or
42  * publicity pertaining to distribution of the software without specific,
43  * written prior permission.  M.I.T. makes no representations about the
44  * suitability of this software for any purpose.  It is provided "as is"
45  * without express or implied warranty.
46  *
47  * Author:  Keith Packard, MIT X Consortium
48  */
49
50 /*
51  * display manager
52  */
53
54 # include       <sys/signal.h>
55 # include       <sys/stat.h>
56 # include       <utmp.h>
57 # include       <time.h>
58 # include       <utime.h>
59 # include       <pwd.h>
60 # include       <varargs.h>
61
62 #if defined (SYSV) || defined (SVR4)
63 #ifndef F_TLOCK
64 # include       <unistd.h>
65 #endif
66 #endif
67 # include       "dm.h"
68 # include       "vgmsg.h"
69
70 #ifdef sun
71 #include <sys/kbio.h>
72 #include <sys/kbd.h>
73 #endif
74
75 #ifndef sigmask
76 #define sigmask(m)  (1 << (( m-1)))
77 #endif
78
79
80 /***************************************************************************
81  *
82  *  External variable declarations
83  *
84  ***************************************************************************/
85
86 #if defined(USL) || defined(__uxp__)
87 extern  int  makepttypair ();
88 #endif
89
90
91 /***************************************************************************
92  *
93  *  Local procedure declarations
94  *
95  ***************************************************************************/
96
97 static void CheckDisplayStatus( struct display *d) ;
98 static void CheckRestartTime( void ) ;
99 static void ChildNotify( int arg ) ;
100 static void MarkDisplay( struct display *d) ;
101 static void KillDisplay( struct display *d) ;
102 static void MarkShutdownTime( void ) ;
103 static void ProcessChildDeath( int pid, waitType status) ;
104 static void RescanIfMod( void ) ;
105 static void RescanNotify( int arg ) ;
106 static void RescanServers( void ) ;
107 static void RestartDisplay( struct display *d, int forceReserver) ;
108 static int  ScanServers( void ) ;
109 static void SetAccessFileTime( void ) ;
110 static void SetConfigFileTime( void ) ;
111 static int  StartGetty( struct display *d) ;
112 static void StopAll( int arg ) ;
113 static long StorePid( void ) ;
114 static void TerminateProcess( int pid, int sig) ;
115 static void UnlockPidFile( void ) ;
116 static void dtMakeDefaultDir( void );
117 static void dtmkdir(char *dir, mode_t dir_mode);
118
119
120
121
122 /***************************************************************************
123  *
124  *  Global variables
125  *
126  ***************************************************************************/
127 struct passwd   puser;          /* pseudo-user password entry              */
128
129 int             Rescan;
130 static long     ServersModTime, ConfigModTime, AccessFileModTime;
131 int             wakeupTime = -1;
132 char            *progName;
133
134 char            DisplayName[32]="main";
135
136 #ifdef OSFDEBUG
137 int nofork_session = 0;
138 #endif
139
140 #ifndef NOXDMTITLE
141 char *Title;    /* Global argv[0] */
142 int TitleLen;
143 #endif
144
145 static int parent_pid = -1;     /* PID of parent dtlogin process */
146
147
148 /***************************************************************************/
149
150 int 
151 main( int argc, char **argv )
152 {
153     long        oldpid;
154     mode_t      oldumask;
155     struct passwd   *p;         /* pointer to  passwd structure (pwd.h)    */
156     
157     /*
158      *  make sure at least world write access is disabled...
159      */
160     if ( (oldumask = umask(022) & 002) == 002)
161         (void) umask(oldumask);
162
163 #ifndef NOXDMTITLE
164     Title = argv[0];
165     TitleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - Title;
166 #endif
167
168     
169     /*
170      * save program name and path...
171      */
172      
173     if ( (progName = malloc(strlen(argv[0]) + 1)) != NULL )
174         strcpy(progName, argv[0]);
175
176 #if defined(USL) || defined(__uxp__)
177     /* create master slave pair for use in login */
178     if (makepttypair () < 0)
179         {
180         Debug ("Could not create pty for use in login");
181         exit (1);
182         }
183 #endif
184
185      
186     /*
187      * Step 1 - load configuration parameters
188      */
189     InitResources (argc, argv);
190     SetConfigFileTime ();
191     LoadDMResources ();
192     /*
193      * Only allow root to run xdm to avoid problems (HP 700/X version)
194      */
195     if (debugLevel == 0 && getuid() != 0)
196     {
197         fprintf(stderr,
198                 (char *)ReadCatalog(MC_ERROR_SET,MC_BAD_ROOT,MC_DEF_BAD_ROOT),
199                 argv[0]);
200         exit (1);
201     }
202
203     dtMakeDefaultDir(); /** Create /var/dt if needed **/
204     CheckErrorFile();   /** verify that we can open an error log **/
205
206 #ifdef OSFDEBUG
207     if (debugLevel >= 10)
208       nofork_session = 1;
209 #endif
210
211     if (debugLevel == 0 && daemonMode)
212             BecomeDaemon ();
213     if ( (oldpid = StorePid ()) != 0 )
214     {
215         if (oldpid == (long) -1)
216             LogError(
217                 ReadCatalog(MC_LOG_SET,MC_LOG_NO_CREATE,MC_DEF_LOG_NO_CREATE),
218                 pidFile);
219         else
220             LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_LOCK,MC_DEF_LOG_NO_LOCK),
221                  pidFile, oldpid);
222         exit (1);
223     }
224
225     /*
226      * Check if we are restarting too fast...
227      */
228      
229     CheckRestartTime();
230
231
232     /*
233      * Initialize error file, open XDMCP socket, and set up interrupt handlers.
234      */
235      
236     InitErrorLog ();
237     init_session_id ();
238     CreateWellKnownSockets ();
239     parent_pid = getpid();              /* PID of parent dtlogin process */
240     (void) signal (SIGTERM, StopAll);
241     (void) signal (SIGINT, StopAll);
242
243     /*
244      * Set pseudo-user to "nobody". Xserver will be run as that pseudo-user 
245      * rather than root (unless pseudo user is specifically set to another 
246      * user via the Xservers file).
247      */
248      
249     if ( (p = getpwnam ("nobody")) != NULL) {
250         puser = *p;
251     } else {
252         /*
253          * This should not happen, the "nobody" user should always be present.
254          * If it does, fall back to traditional values of the "root" user
255          */
256          puser.pw_uid = 0;
257          puser.pw_gid = 1;
258     }
259
260
261 #ifdef __PASSWD_ETC
262     /*
263      *  Ensure the interrupt handlers are set. The Passwd Etc. libraries 
264      *  (getpwnam()) disable SIGTERM and SIGINT.
265      */
266      
267     (void) signal (SIGTERM, StopAll);
268     (void) signal (SIGINT, StopAll);
269 #endif
270
271
272
273     /*
274      * Step 2 - Read /etc/Xservers and set up
275      *      the socket.
276      *
277      *      Keep a sub-daemon running
278      *      for each entry
279      */
280     SetAccessFileTime ();
281     ScanAccessDatabase ();
282 #if !defined (ENABLE_DYNAMIC_LANGLIST)
283     MakeLangList();
284 #endif /* ENABLE_DYNAMIC_LANGLIST */
285     ScanServers ();
286     StartDisplays ();
287     (void) signal (SIGHUP, RescanNotify);
288 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__uxp__)|| defined (__osf__) || defined(linux)
289     (void) signal (SIGCHLD, ChildNotify);
290 #endif
291     while (AnyWellKnownSockets() || AnyDisplaysLeft ())
292     {
293         if (Rescan)
294         {
295             RescanServers ();
296             Rescan = 0;
297         }
298
299         TrimErrorFile();
300
301 #if defined(SYSV) && !defined(hpux) && !defined(_AIX) && !defined(__uxp__)  && !defined (__osf__) && !defined(linux)
302         WaitForChild ();
303 #else
304         WaitForSomething ();
305 #endif
306     }
307     UnlockPidFile();
308     MarkShutdownTime();
309     Debug ("Nothing left to do, exiting\n");
310 }
311
312 static SIGVAL
313 RescanNotify( int arg )
314 {
315     Debug ("Caught SIGHUP\n");
316     Rescan = 1;
317 #if defined(SYSV) || defined(SVR4)
318     signal (SIGHUP, RescanNotify);
319 #endif
320 }
321
322 static int 
323 ScanServers( void )
324 {
325     char        lineBuf[10240];
326     int         len;
327     FILE        *serversFile;
328     struct stat statb;
329     static DisplayType  acceptableTypes[] =
330             { { Local, Permanent, FromFile },
331               { Foreign, Permanent, FromFile },
332             };
333
334 #define NumTypes    (sizeof (acceptableTypes) / sizeof (acceptableTypes[0]))
335
336     if (servers[0] == '/')
337     {
338         serversFile = fopen (servers, "r");
339         if (serversFile == NULL)
340         {
341             LogError(
342                 ReadCatalog(MC_LOG_SET,MC_LOG_NO_SRVACC,MC_DEF_LOG_NO_SRVACC),
343                 servers);
344             return;
345         }
346         if (ServersModTime == 0)
347         {
348             fstat (fileno (serversFile), &statb);
349             ServersModTime = statb.st_mtime;
350         }
351         while (fgets (lineBuf, sizeof (lineBuf)-1, serversFile))
352         {
353             len = strlen (lineBuf);
354             if (lineBuf[len-1] == '\n')
355                 lineBuf[len-1] = '\0';
356             ParseDisplay (lineBuf, acceptableTypes, NumTypes, &puser);
357         }
358         fclose (serversFile);
359     }
360     else
361     {
362         ParseDisplay (servers, acceptableTypes, NumTypes, &puser);
363     }
364 }
365
366 static void 
367 MarkDisplay( struct display *d )
368 {
369     d->state = MissingEntry;
370 }
371
372 static void 
373 KillDisplay( struct display *d )
374 {
375     if (d->name)
376       Debug("Sending HUP to display %s\n", d->name);
377     else
378       Debug("Sending HUP to display ?\n");
379
380     kill(d->pid, SIGHUP);
381 }
382
383 static void 
384 RescanServers( void )
385 {
386     Debug ("Rescanning servers\n");
387
388     LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_REBUILD,MC_DEF_LOG_REBUILD),
389               DEF_NLS_DIR);
390 #if !defined (ENABLE_DYNAMIC_LANGLIST)
391     MakeLangList();
392 #endif /* ENABLE_DYNAMIC_LANGLIST */
393
394     LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_RESCAN,MC_DEF_LOG_RESCAN));
395     ForEachDisplay (MarkDisplay);
396     ForEachDisplay (KillDisplay);
397     ReinitResources ();
398     LoadDMResources ();
399     ScanServers ();
400     SetAccessFileTime ();
401     ScanAccessDatabase ();
402     StartDisplays ();
403 }
404
405 static void
406 SetConfigFileTime( void )
407 {
408     struct stat statb;
409
410     if (stat (config, &statb) != -1)
411         ConfigModTime = statb.st_mtime;
412 }
413
414
415 static void 
416 SetAccessFileTime( void )
417 {
418     struct stat statb;
419
420     if (stat (accessFile, &statb) != -1)
421         AccessFileModTime = statb.st_mtime;
422 }
423
424
425 static void
426 RescanIfMod( void )
427 {
428     struct stat statb;
429
430     if (stat (config, &statb) != -1)
431     {
432         if (statb.st_mtime != ConfigModTime)
433         {
434             Debug ("Config file %s has changed, rereading\n", config);
435             LogInfo(
436                 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADCFG,MC_DEF_LOG_REREADCFG),
437                 config);
438             ConfigModTime = statb.st_mtime;
439             ReinitResources ();
440             LoadDMResources ();
441         }
442     }
443     if (servers[0] == '/' && stat(servers, &statb) != -1)
444     {
445         if (statb.st_mtime != ServersModTime)
446         {
447             Debug ("Servers file %s has changed, rescanning\n", servers);
448             LogInfo(
449                 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADSRV,MC_DEF_LOG_REREADSRV),
450                 servers);
451             ServersModTime = statb.st_mtime;
452             ForEachDisplay (MarkDisplay);
453             ScanServers ();
454         }
455     }
456
457     if (accessFile && accessFile[0] && stat (accessFile, &statb) != -1)
458     {
459         if (statb.st_mtime != AccessFileModTime)
460         {
461             Debug ("Access file %s has changed, rereading\n", accessFile);
462             LogInfo(
463                 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADACC,MC_DEF_LOG_REREADACC),
464                 accessFile);
465             AccessFileModTime = statb.st_mtime;
466             ScanAccessDatabase ();
467         }
468     }
469     
470 }
471
472 /*
473  * catch a SIGTERM, kill all displays and exit
474  */
475
476 static int    dt_shutdown = 0;
477
478 static SIGVAL
479 StopAll( int arg )
480 {
481     if (parent_pid != getpid())
482     {
483         /*
484          * we got caught in a race condition - we are really a
485          * child dtlogin process that has been killed by the parent
486          * dtlogin process before we got a chance to return from
487          * fork() and remove this signal handler
488          */
489         Debug ("Child dtlogin caught signal %d before it could become a real child\n", arg);
490         (void) signal (arg, SIG_DFL);           /* ensure no more handler */
491         TerminateProcess (getpid(), arg);       /* and send signal again */
492         return;
493     }
494
495     Debug ("Shutting down entire manager\n");
496     DestroyWellKnownSockets ();
497     dt_shutdown = 1;
498     MarkShutdownTime();
499     ForEachDisplay (StopDisplay);
500 #if defined(SYSV) || defined(SVR4)
501     /* to avoid another one from killing us unceremoniously */
502     (void) signal (SIGTERM, StopAll);
503     (void) signal (SIGINT, StopAll);
504 #endif
505 }
506
507 /*
508  * notice that a child has died and may need another
509  * sub-daemon started
510  */
511
512 int     ChildReady = 0;
513
514 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__uxp__) || defined (__osf__) || defined(linux)
515 static SIGVAL
516 ChildNotify( int arg )
517 {
518     ChildReady = 1;
519 }
520 #endif
521
522
523 /*
524     In HP-UX, SIGCHLDs are queued rather than lost if we are in the middle
525     of processing one (see SIGNAL(5), WARNINGS). The following code relies
526     upon this.
527     
528     If we have a socket, then we are using "select" to block
529     (WaitForSomething) rather than "wait". If a child dies, ChildReady is
530     set and the select unblocks. We then loop, processing the child that
531     died plus any that die while we are processing others. Finally we
532     activate the signal handler again and go around one more time in case a
533     child died right before activating the signal handler.
534 */
535
536 void
537 WaitForChild( void )
538 {
539     int         pid;
540     waitType    status;
541     int         mask;
542
543 #if defined(SYSV) || defined(SVR4)  || defined(hpux)
544
545     if (AnyWellKnownSockets()) {
546         while ( ChildReady ) {
547 #ifdef SVR4
548            while ((pid = waitpid((pid_t) -1, &status, WNOHANG)) > 0 )
549 #else
550             while ((pid = wait3 (&status, WNOHANG, NULL)) > 0 )
551 #endif
552                 ProcessChildDeath(pid, status);
553
554             ChildReady = 0;
555             (void) signal (SIGCHLD, ChildNotify);
556             sleep(1);
557         }
558     }
559     else {
560         /* XXX classic sysV signal race condition here with RescanNotify */
561         if ((pid = wait (&status)) != -1)
562             ProcessChildDeath(pid, status);
563     }
564
565 #else
566     mask = sigblock (sigmask (SIGCHLD) | sigmask (SIGHUP));
567     Debug ("Signals blocked, mask was 0x%x\n", mask);
568     if (!ChildReady && !Rescan)
569         sigpause (mask);
570     ChildReady = 0;
571     sigsetmask (mask);
572
573     while ((pid = wait3 (&status, WNOHANG, (struct rusage *) 0)) > 0)
574         ProcessChildDeath(pid, status);
575 #endif
576
577     StartDisplays ();
578 }
579         
580
581 static void 
582 ProcessChildDeath( int pid, waitType status )
583 {
584     struct display      *d;
585
586
587         Debug ("Processing child death, pid = %d\n", pid);
588         if (autoRescan)
589             RescanIfMod ();
590
591         if ( (d = FindDisplayByPid (pid)) != 0 ) {
592             d->pid = -1;
593
594             /*
595              *  do process accounting...
596              */
597
598             Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
599
600
601             /*
602              *  make sure authorization file is deleted...
603              */
604 /*
605              
606             if (d->authorization && d->authFile) {
607                 (void) unlink (d->authFile);
608             }
609 */
610
611
612
613
614             /*
615              *  reset "startTries" ...
616              *  
617              *  Local displays:   Only for clean exits of the server
618              *  Foreign displays: Always except for OPENFAILED_DISPLAY
619              *
620              *  Note: if startTries expires and a "getty" is run on the local
621              *        display, startTries will be reset to zero before 
622              *        attempting to restart the server.
623              */
624         
625             switch (waitVal (status)) {
626             case OBEYSESS_DISPLAY:
627             case RESERVER_DISPLAY:
628                 d->startTries = 0;
629                 break;
630
631             case OPENFAILED_DISPLAY:
632                 break;
633
634             default:
635                 if (d->displayType.location != Local )
636                     d->startTries = 0;
637                 break;
638
639             }
640
641
642
643             /*
644              *  process exit status...
645              */
646              
647             switch (waitVal (status)) {
648             case UNMANAGE_DISPLAY:
649                 Debug ("Display exited with UNMANAGE_DISPLAY\n");
650                 StopDisplay (d);
651                 break;
652
653             case OBEYSESS_DISPLAY:
654                 Debug ("Display exited with (check)OBEYSESS_DISPLAY\n");
655                 if (d->displayType.lifetime != Permanent || d->status == zombie)
656                     StopDisplay (d);
657                 else
658                     RestartDisplay (d, FALSE);
659                 break;
660
661             default:
662                 Debug ("Display exited with unknown status %d\n", waitVal(status));
663                 LogError ((unsigned char *)"Unknown session exit code %d from process %d\n",
664                           waitVal (status), pid);
665                 StopDisplay (d);
666                 break;
667
668             case OPENFAILED_DISPLAY:
669                 Debug ("Display exited with OPENFAILED_DISPLAY\n");
670                 if (d->displayType.origin == FromXDMCP)
671                     SendFailed (d, "Cannot open display");
672
673                 if (d->displayType.location != Local)
674                     d->startTries++;
675
676                 if (d->displayType.origin == FromXDMCP ||
677                     d->status == zombie ||
678                     d->startTries >= d->startAttempts)
679                     StopDisplay (d);
680                 else
681                     RestartDisplay (d, TRUE);
682
683                 break;
684
685             case RESERVER_DISPLAY:
686                 Debug ("Display exited with RESERVER_DISPLAY\n");
687                 if (d->displayType.origin == FromXDMCP || d->status == zombie)
688                     StopDisplay(d);
689                 else
690                     RestartDisplay (d, TRUE);
691                 break;
692
693             case waitCompose (SIGTERM,0,0):
694                 Debug ("Display exited on SIGTERM\n");
695                 if (d->displayType.origin == FromXDMCP || d->status == zombie)
696                     StopDisplay(d);
697                 else
698                     RestartDisplay (d, TRUE);
699                 break;
700
701             case REMANAGE_DISPLAY:
702                 Debug ("Display exited with REMANAGE_DISPLAY\n");
703                 /*
704                  * XDMCP will restart the session if the display
705                  * requests it
706                  */
707                 if (d->displayType.origin == FromXDMCP || d->status == zombie)
708                     StopDisplay(d);
709                 else
710                     RestartDisplay (d, FALSE);
711                 break;
712
713             case SUSPEND_DISPLAY:
714                 Debug ("Display exited with SUSPEND_DISPLAY\n");
715                 if (d->displayType.location == Local)
716                     StopDisplay(d);
717                 else
718                     RestartDisplay (d, FALSE);
719
720                 break;
721             }
722         }
723         else if ( (d = FindDisplayByServerPid (pid)) != 0 )
724         {
725             d->serverPid = -1;
726
727             /*
728              *  do process accounting...
729              */
730
731             Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
732
733             switch (d->status)
734             {
735             case zombie:
736                 Debug ("Zombie server reaped, removing display %s\n", d->name);
737                 RemoveDisplay (d);
738                 break;
739             case phoenix:
740                 Debug ("Phoenix server arises, restarting display %s\n", d->name);
741                 d->status = notRunning;
742                 break;
743             case running:
744                 Debug ("Server for display %s terminated unexpectedly, status %d\n", d->name, waitVal (status));
745                 LogError ((unsigned char *)"Server for display %s terminated unexpectedly %d\n",
746                            d->name, waitVal(status) );
747                 if (d->pid != -1)
748                 {
749                     Debug ("Terminating session pid %d\n", d->pid);
750                     TerminateProcess (d->pid, SIGTERM);
751                 }               
752                 break;
753             case notRunning:
754                 Debug ("Server exited for notRunning session on display %s\n", d->name);
755                 break;
756             case suspended:
757                 Debug ("Server for display %s is suspended\n", d->name);
758                 if (!StartGetty(d))
759                     d->status = notRunning;
760                 break;
761             }
762         }
763         else
764         {
765             Debug ("Unknown child termination, status %d\n", waitVal (status));
766         }
767 }
768
769 static void 
770 CheckDisplayStatus( struct display *d )
771 {
772
773     if (d->displayType.origin == FromFile)
774     {
775         switch (d->state) {
776         case MissingEntry:
777             dt_shutdown = 1;
778             StopDisplay (d);
779             dt_shutdown = 0;
780             break;
781         case NewEntry:
782             d->state = OldEntry;
783         case OldEntry:
784             Debug("Check %s: status=%d wakeupTime=%d\n", d->name,
785                   d->status, wakeupTime);
786             if (d->status == suspended && wakeupTime >= 0)
787                 if ( GettyRunning(d) || (strcmp(d->gettyLine,"??") == 0))
788                     if ( wakeupTime == 0 ) {
789                         Debug("Polling of suspended server %s started.\n",
790                                 d->name);
791
792                         wakeupTime = (wakeupInterval < 10
793                                             ?   3 * wakeupInterval
794                                             :   2 * wakeupInterval );
795                     }
796                     else {
797                         Debug("Polling of suspended server %s stopped.\n",
798                                 d->name);
799                         wakeupTime = -1;                /* disable polling */
800                         d->status = notRunning;         /* restart server  */
801                         d->startTries = 0;
802                         if ( !dt_shutdown ) GettyMessage(d,2);
803                     }
804                 else {
805                     Debug("Polling of suspended server %s continued.\n",
806                            d->name);
807                     wakeupTime = wakeupInterval;        /* continue polling*/
808                 }
809
810             if (d->status == notRunning)
811                 StartDisplay (d);
812             break;
813         }
814     }
815 }
816
817 void
818 StartDisplays( void )
819 {
820     ForEachDisplay (CheckDisplayStatus);
821 }
822
823 int 
824 StartDisplay(
825         struct display *d )
826 {
827     waitType  status;
828     int pid;
829     char* authFile_str;
830     char start_fbconsole[1024];
831     char buff[128];
832
833     Debug ("StartDisplay(): %s\n", d->name);
834
835     bzero(&status, sizeof(waitType));
836     if (d->authFile == NULL) 
837         authFile_str = "NULL"; 
838     else
839         authFile_str = d->authFile;
840
841     Debug("(Old StartDisplay) d->authfile %s; authDir %s\n",
842           authFile_str, authDir);
843
844     /*
845      * The following call to RemoveDisplay is to catch race conditions during
846      * shutdown. There is no point in starting a display if Dtlogin is in the
847      * process of shutting down...
848      */
849     if (d->displayType.origin == FromFile && dt_shutdown ) {
850         RemoveDisplay(d);
851         return;
852     }
853     
854     {
855       /* make a backup of the authFile before loading resources and       */
856       /* copy it back to authFile field od display structure for X server */
857       /* to reread the host database list on reset                          */
858       /* RK     11.22.93                                                    */
859       char bkup[50];
860
861       bkup[0] = '\0';
862       if (d->authFile)
863         strcpy(bkup ,d->authFile);
864
865       LoadDisplayResources (d);
866
867       /* The Xserver may NOT have been killed, so reuse the authFile.  */
868       if (NULL == d->authFile &&
869           0 < strlen(bkup) &&
870           0 == strncmp(authDir, bkup, strlen(authDir)))
871         d->authFile= (char *) strdup(bkup);
872
873       if (d->authFile == NULL) 
874         authFile_str = "NULL"; 
875       else
876         authFile_str = d->authFile;
877
878       Debug("(Mid StartDisplay) d->authfile %s; authDir %s; bkup %s\n",
879             authFile_str, authDir, bkup);
880     }
881
882     if (d->displayType.location == Local)
883     {
884         /* don't bother pinging local displays; we'll
885          * certainly notice when they exit
886          */
887         d->pingInterval = 0;
888         if (d->authorize)
889         {
890             Debug ("SetLocalAuthorization %s, auth %s\n",
891                     d->name, d->authNames);
892
893             SetLocalAuthorization (d);
894
895             /*
896              * reset the server after writing the authorization information
897              * to make it read the file (for compatibility with old
898              * servers which read auth file only on reset instead of
899              * at first connection)
900              */
901             if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
902                 kill (d->serverPid, d->resetSignal);
903         }
904
905 #ifndef __apollo
906         /*
907          *  initialize d->utmpId. Check to see if anyone else is using
908          *  the requested ID. Always allow the first request for "dt" to
909          *  succeed as utmp may have become corrupted.
910          */
911
912         if (d->utmpId == NULL) {
913             static int firsttime = 1;
914             static char letters[] = "0123456789abcdefghijklmnopqrstuvwxyzz";
915             char *t;        
916
917             d->utmpId = malloc(5);
918             strcpy(d->utmpId, UTMPREC_PREFIX);
919             d->utmpId[4] = '\0';
920             
921             t = letters;
922             
923             do {
924                 if ( firsttime || UtmpIdOpen(d->utmpId)) {
925                     firsttime = 0;
926                     break;
927                 }               
928                 else {
929                     strncpy(&(d->utmpId[strlen(d->utmpId)]), t++, 1);
930                 }
931             } while (*t != NULL);
932
933             if (*t == NULL) {
934                 Debug ("All DT utmp IDs already in use. Removing display %s\n",
935                         d->name);
936                 LogError ((unsigned char *)"All DT utmp IDs already in use. Removing display %s\n",
937                         d->name);
938                 RemoveDisplay(d);
939                 return;
940             }
941         }
942 #endif
943
944         /*
945          *  set d->gettyLine to "console" for display ":0" if it is not 
946          *  already set...
947          */
948
949         if (! d->gettyLine || strlen(d->gettyLine) == 0 ) {
950             char *p;
951             
952             if ( (p = index(d->name,':')) != NULL &&
953                  (  strncmp(++p,"0",1) == 0 )) {
954
955                 d->gettyLine  = (char *) malloc(8);
956                 strcpy(d->gettyLine,  "console");
957             }
958             else {
959                 d->gettyLine  = (char *) malloc(3);
960                 strcpy(d->gettyLine,  "??");
961             }
962         }
963
964
965         /*
966          *  if gettyLine is set to "console", set gettySpeed to "console" also
967          */
968                         
969         if (d->gettyLine && (strcmp(d->gettyLine, "console") == 0 ) ) {
970             if (d->gettySpeed) 
971                 free((char *) d->gettySpeed);
972
973             d->gettySpeed = (char *) malloc(8);
974             if (d->gettySpeed)
975                 strcpy(d->gettySpeed, "console");
976         }
977                     
978
979         /*
980          *  start server. If it cannot be started and this is the console,
981          *  run a getty...
982          */
983          
984         Debug("Attempting to start server for %s.  startTries = %d\n", 
985                 d->name, d->startTries);
986
987         if (d->serverPid == -1) {
988             static int bootup = 0;
989             
990             while (bootup++ < 5) {
991                 if (GettyRunning(d)) {
992                     GettyMessage(d,3);
993                     bootup = 5;
994                     break;
995                 }
996                 else {
997                     sleep(1);
998                 }
999             }
1000         }
1001         
1002         if (d->serverPid == -1 && 
1003             (d->startTries++ >= d->startAttempts ||
1004              !StartServer (d)))
1005         {
1006             LogError ((unsigned char *)"Server for display %s can't be started.\n", d->name);
1007
1008             d->serverPid = -1;
1009
1010             GettyMessage(d,4);
1011
1012             if (!StartGetty(d))
1013                 RemoveDisplay (d);
1014             return;
1015         }
1016     }
1017     else
1018     {
1019         /* this will only happen when using XDMCP */
1020         if (d->authorizations)
1021             SaveServerAuthorizations (d, d->authorizations, d->authNum);
1022
1023         /*
1024          *  Generate a utmp ID address for a foreign display. Use the last
1025          *  four characters of the DISPLAY name, shifting left if they
1026          *  are already in use...
1027          */
1028  
1029         if (d->utmpId == NULL) {
1030             int i;
1031             char *p, *q;
1032             struct utmp *u;
1033             
1034             d->utmpId = malloc(sizeof(u->ut_id) +1);
1035  
1036             i = strlen (d->name);
1037             if (i >= sizeof (u->ut_id))
1038                 i -= sizeof (u->ut_id);
1039             else
1040                 i = 0;
1041  
1042             for ( p = d->name, q = d->name + i; p <= q; q-- ) {
1043                 (void) strncpy (d->utmpId, q, sizeof (u->ut_id));
1044                 d->utmpId[sizeof(u->ut_id)] = '\0';
1045                 if (UtmpIdOpen(d->utmpId))
1046                     break;
1047             }
1048
1049 #ifdef DEF_NETWORK_DEV
1050             /*
1051              * If "networkDev" does not start with "/dev/" then foreign
1052              * accounting is turned off. Return utmpId to NULL.
1053              */
1054             if (networkDev && strncmp(networkDev,"/dev/",5) !=0 ) {
1055                 free(d->utmpId);
1056                 d->utmpId = NULL;
1057             }           
1058 #endif       
1059         }
1060     }
1061
1062     if (NULL == d->authFile)
1063       authFile_str = "NULL";
1064     else
1065       authFile_str = d->authFile;
1066
1067     Debug("(New StartDisplay) d->authfile %s; authDir %s\n",
1068           authFile_str, authDir);
1069
1070     /*
1071      *  make sure stderr is pointing to the current error log file...
1072      */
1073     SyncErrorFile(0);
1074
1075     
1076 #ifdef OSFDEBUG
1077     if (!nofork_session)
1078         pid = fork ();
1079     else
1080         pid = 0;
1081     switch (pid)
1082 #else
1083     switch (pid = fork ())
1084 #endif
1085     {
1086     case 0:
1087 #ifdef OSFDEBUG
1088         if (!nofork_session) {
1089             CleanUpChild ();
1090             signal (SIGPIPE, SIG_IGN);
1091         }
1092 #else
1093         CleanUpChild ();
1094         signal (SIGPIPE, SIG_IGN);
1095 #endif
1096
1097         /* 
1098          * set global display name for Debug()
1099          */
1100          
1101         {
1102             char *p, *s, *t;
1103             
1104             p = DisplayName;
1105             
1106             strncpy(p, d->name, sizeof(DisplayName));
1107             DisplayName[sizeof(DisplayName)-1] = '\0';
1108             
1109             if ( (s = strchr(p,':')) != NULL )
1110                 if ( (t = strchr(p,'.')) != NULL )
1111                     strcpy(t,s);
1112         }
1113
1114         
1115         SetAuthorization (d);
1116
1117         /*
1118          * do process accounting...
1119          */
1120
1121         {
1122             char *line = (d->displayType.location==Local) 
1123                 ? d->gettyLine : d->name;
1124 #ifdef DEF_NETWORK_DEV
1125             if (d->displayType.location != Local &&
1126                 networkDev && !strncmp(networkDev,"/dev/",5))
1127             {
1128                 char *devname;
1129                 int devexists;
1130                 struct stat devinfo;
1131                 devname = networkDev; /* networkDev resource */
1132
1133                 devexists = (lstat(devname,&devinfo)==0);
1134
1135                 if (!devexists && (MK_NETWORK_DEV(devname) < 0)) {
1136                     Debug("Creation of file '%s' failed:\n  %s (%d)\n",
1137                         devname,strerror(errno),errno);
1138                 } else {
1139
1140                     for (line=devname; *line; line++);
1141                     while (line>devname && *line!='/') line--;
1142                     if (*line=='/') line++;
1143
1144                     Debug("Using pseudo-tty %s; line=%s\n",
1145                         devname,line);
1146                 }
1147             }
1148 #endif
1149             Account(d, "LOGIN", line, getpid(), LOGIN_PROCESS, status);
1150         }
1151
1152         if (!WaitForServer (d))
1153             exit (OPENFAILED_DISPLAY);
1154
1155         /*
1156          * start the fallback console, if the display is local..
1157          * 
1158          * if the display is remote, fbconsole should be started on
1159          * remote host. 
1160          */
1161 #ifdef sun
1162         if (d->displayType.location==Local) {
1163             if (d->authFile && strlen(d->authFile) > 0 ) {
1164                 strcpy(buff, "XAUTHORITY=");
1165                 strcat(buff, d->authFile);
1166                 putenv(buff);
1167             }
1168             sprintf(start_fbconsole,"%s -d %s &",FBCONSOLE, d->name);
1169
1170             if(system(start_fbconsole) == -1)
1171                Debug("Failed to start the fallback console - %s\n",FBCONSOLE);
1172         }
1173 #endif
1174
1175         if (d->useChooser)
1176             RunChooser (d);
1177         else
1178             ManageSession (d);
1179         exit (REMANAGE_DISPLAY);
1180     case -1:
1181         break;
1182     default:
1183         Debug ("Child manager process started for %s. pid = %d\n", 
1184                 d->name, pid);
1185         d->pid = pid;
1186         d->status = running;
1187         break;
1188     }
1189 }
1190
1191 static void
1192 TerminateProcess(int pid, int sig )
1193 {
1194     kill (pid, sig);
1195 #ifdef SIGCONT
1196     kill (pid, SIGCONT);
1197 #endif
1198 }
1199
1200 /*
1201  * transition from running to zombie, suspended, or deleted
1202  */
1203
1204 void 
1205 StopDisplay( struct display *d )
1206 {
1207     waitType      status;
1208
1209     bzero(&status, sizeof(waitType));
1210     Debug("StopDisplay(): %s, server pid = %d, manager pid = %d, dt_shutdown = %d\n",
1211           d->name, d->serverPid, d->pid, dt_shutdown);
1212            
1213     if (d->serverPid != -1)
1214         /* don't remove the console */
1215         if ((d->displayType.location == Local) && !dt_shutdown ) 
1216             d->status = suspended;
1217         else
1218             d->status = zombie; /* be careful about race conditions */
1219
1220     if (d->pid != -1)
1221         TerminateProcess (d->pid, SIGTERM);
1222
1223     if (d->serverPid != -1) {
1224         TerminateProcess (d->serverPid, d->termSignal);
1225 #ifdef sun
1226         {
1227             int kbd_fd;
1228             int translate=TR_ASCII;
1229
1230             Debug ("Resetting keyboard\n");
1231
1232             if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) {
1233                 Debug("/dev/kbd open failed\n");
1234             } else if (ioctl(kbd_fd, KIOCTRANS, (caddr_t) &translate)) {
1235                 Debug("Could not set /dev/kbd back to ASCII mode\n");
1236             }
1237         }
1238 #endif
1239     }
1240     else 
1241         if ((d->displayType.location == Local) || !dt_shutdown ) {
1242             /* don't remove the console */
1243             Account(d, NULL, NULL, 0, DEAD_PROCESS, status);
1244             RemoveDisplay (d);
1245         }           
1246 }
1247
1248
1249 /*
1250  * transition from running to phoenix or notRunning
1251  */
1252
1253 static void 
1254 RestartDisplay( struct display *d, int forceReserver )
1255 {
1256     if (d->serverPid != -1 && (forceReserver || d->terminateServer))
1257     {
1258         TerminateProcess (d->serverPid, d->termSignal);
1259         d->status = phoenix;
1260     }
1261     else
1262     {
1263         d->status = notRunning;
1264     }
1265 }
1266
1267 static FD_TYPE  CloseMask;
1268 static int      max;
1269
1270 void
1271 RegisterCloseOnFork( int fd )
1272 {
1273     FD_SET (fd, &CloseMask);
1274     if (fd > max)
1275         max = fd;
1276 }
1277
1278 #if 0           /* utility routine: activate if needed...                  */
1279 int 
1280 CloseOnFork( void )
1281 {
1282     FD_CLR (fd, &CloseMask);
1283     if (fd == max) {
1284         while (--fd >= 0)
1285             if (FD_ISSET (fd, &CloseMask))
1286                 break;
1287         max = fd;
1288     }
1289 }
1290 #endif
1291
1292 CloseOnFork ()
1293 {
1294     int fd;
1295
1296     for (fd = 0; fd <= max; fd++)
1297         if (FD_ISSET (fd, &CloseMask))
1298             close (fd);
1299     FD_ZERO (&CloseMask);
1300     max = 0;
1301 }
1302
1303 static int  pidFd;
1304 static FILE *pidFilePtr;
1305
1306 static long 
1307 StorePid( void )
1308 {
1309     long        oldpid;
1310
1311     if (pidFile && pidFile[0] != '\0') {
1312         pidFd = open (pidFile, 2);
1313         if (pidFd == -1 && errno == ENOENT)
1314         {
1315             /*
1316              * HP OSF/1 will not allow an fdopen 
1317              * of a file descriptor handed back by creat(2).
1318              *  The workaround is to close the created file, and 
1319              * open it Read/Write.  This will be transparent to HP-UX.
1320              */
1321             pidFd = creat (pidFile, 0644);
1322             close( pidFd );
1323             pidFd = open (pidFile, 2);
1324         }
1325         if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+")))
1326         {
1327             LogError ((unsigned char *)"Process ID file %s cannot be opened\n",
1328                       pidFile);
1329             return -1;
1330         }
1331         if (fscanf (pidFilePtr, "%ld", &oldpid) != 1)
1332             oldpid = -1;
1333         fseek (pidFilePtr, 0l, 0);
1334         if (lockPidFile)
1335         {
1336 #if defined (SYSV) || defined (SVR4)
1337             if (lockf (pidFd, F_TLOCK, 0) == -1)
1338             {
1339                 if ((errno == EAGAIN) || (errno == EACCES))
1340                     return oldpid;
1341                 else
1342                     return -1;
1343             }
1344 #else
1345             if (flock (pidFd, LOCK_EX|LOCK_NB) == -1)
1346             {
1347                 if (errno == EWOULDBLOCK)
1348                     return oldpid;
1349                 else
1350                     return -1;
1351             }
1352 #endif
1353         }
1354
1355         /*
1356          * HPUX releases the lock on ANY close of the file, not just the
1357          * one that established the lock. -prr
1358          */
1359         /*      close(creat(pidFile, 0644)); */
1360
1361         (void) creat(pidFile, 0644);
1362         fprintf (pidFilePtr, "%ld\n", (long)getpid ());
1363         (void) fflush(pidFilePtr);
1364         RegisterCloseOnFork(pidFd);
1365     }
1366     return 0;
1367 }
1368
1369 static void
1370 UnlockPidFile( void )
1371 {
1372     if (lockPidFile)
1373 #if defined (SYSV) || defined (SVR4)
1374         lockf (pidFd, F_ULOCK, 0);
1375 #else
1376         flock (pidFd, LOCK_UN);
1377 #endif
1378     close (pidFd);
1379     fclose (pidFilePtr);
1380 }
1381
1382 #ifdef oldcode
1383 /*VARARGS*/
1384 SetTitle (va_alist)
1385 va_dcl
1386 {
1387 #ifndef NOXDMTITLE
1388     char        *p = Title;
1389     int         left = TitleLen;
1390     char        *s;
1391     va_list     args;
1392
1393     va_start(args);
1394     *p++ = '-';
1395     --left;
1396     while (s = va_arg (args, char *))
1397     {
1398         while (*s && left > 0)
1399         {
1400             *p++ = *s++;
1401             left--;
1402         }
1403     }
1404     while (left > 0)
1405     {
1406         *p++ = ' ';
1407         --left;
1408     }
1409     va_end(args);
1410 #endif  
1411 }
1412 #endif
1413
1414 int 
1415 SetTitle( char *name, char *ptr )
1416 {
1417 #ifndef NOXDMTITLE
1418     char        *p, *s, *t;
1419     int         length;
1420
1421
1422     /*
1423      *  remove domain qualifiers and screens from name...
1424      */
1425
1426     if ( (p = malloc(strlen(name) + 1)) == NULL) return;
1427     strcpy(p, name);
1428
1429     if ( (s = strchr(p,':')) == NULL ) {
1430         free(p);
1431         return;
1432     }
1433     
1434     if ( (t = strchr(s,'.')) != NULL )
1435         *t = '\0';
1436
1437     if ( (t = strchr(p,'.')) != NULL )
1438         strcpy(t,s);
1439     
1440     /*
1441      *  if there is enough room shift program name to left,
1442      *  then append display name in remaining space.
1443      */
1444
1445     s = Title;
1446     length = strlen(s);
1447     
1448     t = strrchr(s, '/');
1449     if ( (t != NULL) && ((t-s+1) >= (strlen(p) + 3)) ) {
1450         t++;
1451
1452         strcpy(s,t);            /* "program"                       */
1453         strcat(s," <");         /* "program <"                     */
1454         strcat(s,p);            /* "program <displayName"          */
1455         strcat(s,">");          /* "program <displayName>"         */
1456
1457         t = s + strlen(s);
1458         length = length - strlen(s);
1459         while (length > 0){
1460             *t++ = ' ';
1461             length--;
1462         }
1463     }
1464
1465     free(p);
1466 #endif
1467 }
1468
1469
1470 /*****************************************************************************
1471 *    StartGetty
1472 *    
1473 *    Start a "getty" running on the console...
1474 *
1475 *****************************************************************************/
1476
1477 #if defined (_AIX) && defined (_POWER) || defined (__osf__)
1478 #define GETTYPATH "/usr/sbin/getty"
1479 #elif !defined (__apollo)
1480 #define GETTYPATH "/etc/getty"
1481 #endif
1482
1483 static int 
1484 StartGetty( struct display *d )
1485 {
1486     int         pid;
1487     char tynm[20];
1488     waitType  status;
1489
1490     Debug ("StartGetty(): %s\n", d->name);
1491
1492     bzero(&status, sizeof(waitType));
1493     /*
1494      * ensure that server is known dead...
1495      */
1496
1497     d->serverPid = -1;
1498
1499 #if !defined(GETTYPATH)
1500     return FALSE;
1501 #else
1502
1503     /*
1504      * check to see if we have a valid device (at least a non-null name)...
1505      */
1506
1507     if ( d->gettyLine                   && 
1508         (strlen(d->gettyLine) > 0)      &&
1509         (strcmp(d->gettyLine,"??") != 0)        )
1510         ;
1511     else
1512         return FALSE;
1513
1514
1515     /*
1516      * if there is already a getty running on the device, set up
1517      * to start watching it. When it exits, restart the server...
1518      */
1519
1520     if ( GettyRunning(d) ) {
1521         d->status = suspended;          /* set up to restart server        */
1522         wakeupTime = 0;                 /* enable polling                  */
1523
1524         sleep(1);                       /* wait for fbconsole to go away   */
1525         GettyMessage(d,1);              /* print a help message            */
1526
1527         return TRUE;
1528     }
1529
1530     
1531     /*
1532      * there is no getty running on the device, try to start one...
1533      */
1534
1535     d->status = phoenix;                /* set up to restart server        */
1536     d->startTries = 0;
1537     
1538     switch (pid = fork ()) {
1539     case 0:
1540         CleanUpChild ();
1541
1542         /*
1543          *  do process accounting...
1544          */
1545         Account(d, "LOGIN", NULL, getpid(), LOGIN_PROCESS, status);
1546
1547
1548         #ifdef _AIX
1549         /* The tty argument for getty on AIX must be of the form "/dev/any tty"
1550            and so the following logic
1551            Raghu krovvidi 07.07.93
1552          */
1553          strcpy(tynm,"/dev/");
1554          strcat(tynm,d->gettyLine); 
1555         #else
1556          strcpy(tynm, d->gettyLine);
1557         #endif
1558
1559         Debug(" execing getty on %s\n",tynm);
1560         execl(GETTYPATH, "getty", tynm, d->gettySpeed, (char *)0);
1561         LogError ((unsigned char *)"Can not execute %s for %s: errno = %d\n",
1562                    GETTYPATH, d->name, errno);
1563
1564         exit (UNMANAGE_DISPLAY);
1565
1566     case -1:
1567         Debug ("Fork of /etc/getty failed %s\n", d->name);
1568         LogError ((unsigned char *)"Can not fork to execute /etc/getty %s\n", d->name);
1569         return FALSE;
1570
1571     default:
1572         break;
1573     }
1574
1575     Debug ("/etc/getty started on %s\n", d->name);
1576     d->serverPid = pid;
1577     return TRUE;
1578 #endif /* GETTYPATH not defined */
1579 }
1580
1581  
1582 /***************************************************************************
1583  *
1584  *  GettyMessage
1585  *
1586  *  Print a message on the display device when going into No Windows mode.
1587  *
1588  ***************************************************************************/
1589
1590 void
1591 GettyMessage( struct display *d, int msgnum )
1592 {
1593     FILE *tf;
1594     char buf[128];
1595
1596     strcpy(buf,"/dev/");
1597     strcat(buf,d->gettyLine);
1598     
1599     if ( (tf = fopen (buf, "a")) != NULL) {
1600         fprintf (tf, 
1601           "\r\n\r\n*****************************************************************************\r\n*\r\n");
1602
1603         switch (msgnum) {
1604         case 1:
1605         
1606           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS1_LABEL,MC_DEF_SUS1_LABEL));
1607
1608           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS2_LABEL,MC_DEF_SUS2_LABEL));
1609
1610           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS3_LABEL,MC_DEF_SUS3_LABEL));
1611
1612           break;
1613           
1614         case 2:
1615         
1616           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_RES_LABEL,MC_DEF_RES_LABEL));
1617
1618           break;
1619           
1620         case 3:
1621         
1622           fprintf(tf,
1623                 (char *)ReadCatalog(MC_LABEL_SET,MC_START_LBLDPY,MC_DEF_START_LBLDPY),
1624                 d->name);
1625
1626           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_WAIT_LABEL,MC_DEF_WAIT_LABEL));
1627
1628           break;
1629           
1630         case 4:
1631         
1632           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_X_LABEL,MC_DEF_X_LABEL),
1633                 d->name);
1634
1635           break;
1636
1637         }
1638         
1639         fprintf (tf, 
1640           "*****************************************************************************\r\n");
1641
1642
1643         fclose (tf);
1644     }
1645 }
1646
1647
1648 /***************************************************************************
1649  *
1650  *  GettyRunning
1651  *
1652  *  See if a getty process is running against the display device. This
1653  *  routine may need to be rewritten on other platforms if a different
1654  *  mechanism is needed to make the determination.
1655  *
1656  *  Output:  TRUE  == a login process is active on the requested device
1657  *           FALSE == a login process is not active on the device.
1658  *
1659  *  Sets d->gettyState:
1660  *    NONE - no getty running or don't care
1661  *    LOGIN - getty running
1662  *    USER - user logged in on getty
1663  *
1664  *  Note: The check for a getty process running is made by scanning
1665  *        /etc/utmp, looking for a login process on the respective device.
1666  *        However, the child Dtlogin spawned by the master Dtlogin to
1667  *        handle this display also is a "login process" according to
1668  *        /etc/utmp.  It provides a login path and therefore must register
1669  *        itself as so.  If a getty is also running, there are actually two
1670  *        login processes running against the same device at the same time.
1671  *
1672  *        The child Dtlogin dies before the scan of /etc/utmp is made.
1673  *        Provided /etc/utmp is updated correctly, the Dtlogin entry will
1674  *        be marked as dead and will not show up in the scan of /etc/utmp.
1675  ***************************************************************************/
1676
1677 int 
1678 GettyRunning( struct display *d )
1679 {
1680     struct utmp utmp;           /* local struct for new entry              */
1681     struct utmp *u;             /* pointer to entry in utmp file           */
1682     
1683     int         rvalue;         /* return value (TRUE or FALSE)            */
1684     char        buf[32];
1685         
1686     d->gettyState = DM_GETTY_NONE;
1687
1688     /*
1689      * check to see if we have a valid device (at least a non-null name)...
1690      */
1691
1692     if ( d->gettyLine                   && 
1693         (strlen(d->gettyLine) > 0)      &&
1694         (strcmp(d->gettyLine,"??") != 0)        )
1695         ;
1696     else
1697         return FALSE;
1698
1699
1700     bzero(&utmp, sizeof(struct utmp));
1701
1702 #ifdef _AIX
1703    if (!strcmp(d->gettyLine,"console")) {
1704         char *ttynm;
1705         int fd=0;
1706
1707         fd = open("/dev/console",O_RDONLY);
1708         ttynm = ttyname(fd);
1709         ttynm += 5;
1710         strcpy(utmp.ut_line,ttynm);
1711         close(fd);
1712     }
1713     else
1714         strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1715
1716 #else
1717     strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1718 #endif
1719     
1720     Debug("Checking for a getty on line %s.\n", utmp.ut_line);
1721     
1722     setutent();
1723
1724     rvalue = FALSE;
1725     
1726     while ( (u = getutent()) != NULL ) {
1727     
1728         if ((strncmp(u->ut_line, utmp.ut_line, sizeof(u->ut_line)) != 0) ||
1729             (strncmp(u->ut_id,   d->utmpId,    sizeof(u->ut_id))   == 0) )
1730             continue;
1731
1732         switch (u->ut_type) {
1733     
1734         case INIT_PROCESS:      strcpy(buf, "INIT_PROCESS");    break;
1735         case LOGIN_PROCESS:     strcpy(buf, "LOGIN_PROCESS");   break;
1736         case USER_PROCESS:      strcpy(buf, "USER_PROCESS");    break;
1737         case DEAD_PROCESS:      strcpy(buf, "DEAD_PROCESS");    break;
1738         default:                strcpy(buf, "UNKNOWN");         break;
1739         }
1740
1741         Debug("Utmp info: id=%.4s, user=%s, line=%s, pid=%d, type=%s\n",
1742                u->ut_id, u->ut_user, u->ut_line, u->ut_pid, buf);
1743
1744         if ( u->ut_type == INIT_PROCESS || u->ut_type == LOGIN_PROCESS) {
1745           d->gettyState = DM_GETTY_LOGIN;
1746         }
1747         else if (wakeupTime <= 0 && u->ut_type == USER_PROCESS) {
1748           d->gettyState = DM_GETTY_USER;
1749         }
1750      
1751         if (d->gettyState != DM_GETTY_NONE)
1752         {
1753             rvalue = TRUE;
1754             break;
1755         }
1756     }
1757
1758     endutent();
1759     return rvalue;
1760 }
1761
1762
1763  
1764 /***************************************************************************
1765  *
1766  *  CheckRestartTime
1767  *
1768  *  Check if enough time has elapsed since shutdown. 
1769  *
1770  *  This is primarily to work with /etc/shutdown.  When shutdown kills
1771  *  dtlogin (/etc/killall), init immediately restarts it.  Shutdown kills
1772  *  it again and init restarts it.  At each restart, the X-server may start
1773  *  on the local display and then subsequently be killed.  The user sees a
1774  *  flashing screen and sometimes the console is left in an unreset state.
1775  *
1776  *  When Dtlogin shuts down, it touches the access time on the Xservers
1777  *  file.  (MarkShutdownTime()).  This time is then used to determine if
1778  *  sufficient time has elapsed before restarting.
1779  *
1780  ***************************************************************************/
1781
1782 static void
1783 CheckRestartTime( void )
1784 {
1785     struct stat statb;
1786     int         sleeptime;
1787     
1788     if (servers[0] == '/' && stat(servers, &statb) != -1) {
1789
1790         Debug("Checking restart time.\n");
1791         
1792 #ifdef OSFDEBUG
1793 /* only those other systems are this slow :-) */
1794         sleeptime = 6 - (int) (time((time_t *) 0) - statb.st_atime);
1795 #else
1796         sleeptime = 30 - (int) (time((time_t *) 0) - statb.st_atime);
1797 #endif
1798         
1799         if ( sleeptime > 30 ) sleeptime = 30;
1800         
1801         if ( sleeptime > 0 ) {
1802             Debug("Restarting too soon after shutdown. Sleeping %d seconds.\n",
1803                    sleeptime);
1804             sleep (sleeptime);
1805         }
1806     }
1807
1808 }
1809
1810  
1811 /***************************************************************************
1812  *
1813  *  MarkShutdownTime
1814  *
1815  *  Save the time when we shut down to check later for too fast of a restart.
1816  *
1817  ***************************************************************************/
1818
1819 static void
1820 MarkShutdownTime( void )
1821 {
1822     struct stat statb;
1823     struct utimbuf timebuf;
1824     
1825     if (servers[0] == '/' && stat(servers, &statb) != -1) {
1826
1827         Debug("Marking shutdown time.\n");
1828
1829         timebuf.actime = time((time_t *) 0 );
1830         timebuf.modtime = statb.st_mtime;
1831
1832         if ( (utime(servers, &timebuf)) != 0 ) {
1833             Debug("MarkShutdownTime(): utime() error = %d\n", errno);
1834         }
1835     }
1836 }
1837
1838
1839 /***************************************************************************
1840  *
1841  *  dtMakeDefaultDir
1842  *
1843  * Make the default dt directory "/var/dt" if needed.
1844  *
1845  ***************************************************************************/
1846 static void
1847 dtMakeDefaultDir( void )
1848 {
1849     dtmkdir("/var", 0775);
1850     dtmkdir("/var/dt", 0755);
1851     dtmkdir("/var/dt/tmp", 0755);
1852     dtmkdir("/var/dt/appconfig", 0755);
1853     dtmkdir("/var/dt/appconfig/appmanager", 0755);
1854 }
1855
1856 static void
1857 dtmkdir(char *dir, mode_t dir_mode)
1858 {
1859     struct stat file_status;
1860
1861     if ( stat(dir, &file_status) != 0) {
1862         /** try to create it **/
1863         if ( mkdir(dir, dir_mode) == 0) {
1864             chmod(dir, dir_mode);  /** since umask is non-zero **/
1865             Debug("Created dir %s\n", dir);
1866         } else {
1867             LogError((unsigned char *)"Unable to create dir %s\n", dir);
1868         }
1869     } else {
1870         if ( (file_status.st_mode & dir_mode) != dir_mode) {
1871             /** try to set correct permissions **/
1872             if ( chmod(dir, file_status.st_mode | dir_mode) == 0) {
1873                 Debug("Set permissions on %s\n", dir);
1874             } else {
1875                 LogError((unsigned char *)
1876                          "Unable to set permissions on %s\n", dir);
1877             }
1878         }
1879     }
1880 }