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