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