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