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