On Linux no access to pre iso C varargs.h
[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)
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             Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
603
604
605             /*
606              *  make sure authorization file is deleted...
607              */
608 /*
609              
610             if (d->authorization && d->authFile) {
611                 (void) unlink (d->authFile);
612             }
613 */
614
615
616
617
618             /*
619              *  reset "startTries" ...
620              *  
621              *  Local displays:   Only for clean exits of the server
622              *  Foreign displays: Always except for OPENFAILED_DISPLAY
623              *
624              *  Note: if startTries expires and a "getty" is run on the local
625              *        display, startTries will be reset to zero before 
626              *        attempting to restart the server.
627              */
628         
629             switch (waitVal (status)) {
630             case OBEYSESS_DISPLAY:
631             case RESERVER_DISPLAY:
632                 d->startTries = 0;
633                 break;
634
635             case OPENFAILED_DISPLAY:
636                 break;
637
638             default:
639                 if (d->displayType.location != Local )
640                     d->startTries = 0;
641                 break;
642
643             }
644
645
646
647             /*
648              *  process exit status...
649              */
650              
651             switch (waitVal (status)) {
652             case UNMANAGE_DISPLAY:
653                 Debug ("Display exited with UNMANAGE_DISPLAY\n");
654                 StopDisplay (d);
655                 break;
656
657             case OBEYSESS_DISPLAY:
658                 Debug ("Display exited with (check)OBEYSESS_DISPLAY\n");
659                 if (d->displayType.lifetime != Permanent || d->status == zombie)
660                     StopDisplay (d);
661                 else
662                     RestartDisplay (d, FALSE);
663                 break;
664
665             default:
666                 Debug ("Display exited with unknown status %d\n", waitVal(status));
667                 LogError ((unsigned char *)"Unknown session exit code %d from process %d\n",
668                           waitVal (status), pid);
669                 StopDisplay (d);
670                 break;
671
672             case OPENFAILED_DISPLAY:
673                 Debug ("Display exited with OPENFAILED_DISPLAY\n");
674                 if (d->displayType.origin == FromXDMCP)
675                     SendFailed (d, "Cannot open display");
676
677                 if (d->displayType.location != Local)
678                     d->startTries++;
679
680                 if (d->displayType.origin == FromXDMCP ||
681                     d->status == zombie ||
682                     d->startTries >= d->startAttempts)
683                     StopDisplay (d);
684                 else
685                     RestartDisplay (d, TRUE);
686
687                 break;
688
689             case RESERVER_DISPLAY:
690                 Debug ("Display exited with RESERVER_DISPLAY\n");
691                 if (d->displayType.origin == FromXDMCP || d->status == zombie)
692                     StopDisplay(d);
693                 else
694                     RestartDisplay (d, TRUE);
695                 break;
696
697             case waitCompose (SIGTERM,0,0):
698                 Debug ("Display exited on SIGTERM\n");
699                 if (d->displayType.origin == FromXDMCP || d->status == zombie)
700                     StopDisplay(d);
701                 else
702                     RestartDisplay (d, TRUE);
703                 break;
704
705             case REMANAGE_DISPLAY:
706                 Debug ("Display exited with REMANAGE_DISPLAY\n");
707                 /*
708                  * XDMCP will restart the session if the display
709                  * requests it
710                  */
711                 if (d->displayType.origin == FromXDMCP || d->status == zombie)
712                     StopDisplay(d);
713                 else
714                     RestartDisplay (d, FALSE);
715                 break;
716
717             case SUSPEND_DISPLAY:
718                 Debug ("Display exited with SUSPEND_DISPLAY\n");
719                 if (d->displayType.location == Local)
720                     StopDisplay(d);
721                 else
722                     RestartDisplay (d, FALSE);
723
724                 break;
725             }
726         }
727         else if ( (d = FindDisplayByServerPid (pid)) != 0 )
728         {
729             d->serverPid = -1;
730
731             /*
732              *  do process accounting...
733              */
734
735             Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
736
737             switch (d->status)
738             {
739             case zombie:
740                 Debug ("Zombie server reaped, removing display %s\n", d->name);
741                 RemoveDisplay (d);
742                 break;
743             case phoenix:
744                 Debug ("Phoenix server arises, restarting display %s\n", d->name);
745                 d->status = notRunning;
746                 break;
747             case running:
748                 Debug ("Server for display %s terminated unexpectedly, status %d\n", d->name, waitVal (status));
749                 LogError ((unsigned char *)"Server for display %s terminated unexpectedly %d\n",
750                            d->name, waitVal(status) );
751                 if (d->pid != -1)
752                 {
753                     Debug ("Terminating session pid %d\n", d->pid);
754                     TerminateProcess (d->pid, SIGTERM);
755                 }               
756                 break;
757             case notRunning:
758                 Debug ("Server exited for notRunning session on display %s\n", d->name);
759                 break;
760             case suspended:
761                 Debug ("Server for display %s is suspended\n", d->name);
762                 if (!StartGetty(d))
763                     d->status = notRunning;
764                 break;
765             }
766         }
767         else
768         {
769             Debug ("Unknown child termination, status %d\n", waitVal (status));
770         }
771 }
772
773 static void 
774 CheckDisplayStatus( struct display *d )
775 {
776
777     if (d->displayType.origin == FromFile)
778     {
779         switch (d->state) {
780         case MissingEntry:
781             dt_shutdown = 1;
782             StopDisplay (d);
783             dt_shutdown = 0;
784             break;
785         case NewEntry:
786             d->state = OldEntry;
787         case OldEntry:
788             Debug("Check %s: status=%d wakeupTime=%d\n", d->name,
789                   d->status, wakeupTime);
790             if (d->status == suspended && wakeupTime >= 0)
791                 if ( GettyRunning(d) || (strcmp(d->gettyLine,"??") == 0))
792                     if ( wakeupTime == 0 ) {
793                         Debug("Polling of suspended server %s started.\n",
794                                 d->name);
795
796                         wakeupTime = (wakeupInterval < 10
797                                             ?   3 * wakeupInterval
798                                             :   2 * wakeupInterval );
799                     }
800                     else {
801                         Debug("Polling of suspended server %s stopped.\n",
802                                 d->name);
803                         wakeupTime = -1;                /* disable polling */
804                         d->status = notRunning;         /* restart server  */
805                         d->startTries = 0;
806                         if ( !dt_shutdown ) GettyMessage(d,2);
807                     }
808                 else {
809                     Debug("Polling of suspended server %s continued.\n",
810                            d->name);
811                     wakeupTime = wakeupInterval;        /* continue polling*/
812                 }
813
814             if (d->status == notRunning)
815                 StartDisplay (d);
816             break;
817         }
818     }
819 }
820
821 void
822 StartDisplays( void )
823 {
824     ForEachDisplay (CheckDisplayStatus);
825 }
826
827 int 
828 StartDisplay(
829         struct display *d )
830 {
831     waitType  status;
832     int pid;
833     char* authFile_str;
834     char start_fbconsole[1024];
835     char buff[128];
836
837     Debug ("StartDisplay(): %s\n", d->name);
838
839     bzero(&status, sizeof(waitType));
840     if (d->authFile == NULL) 
841         authFile_str = "NULL"; 
842     else
843         authFile_str = d->authFile;
844
845     Debug("(Old StartDisplay) d->authfile %s; authDir %s\n",
846           authFile_str, authDir);
847
848     /*
849      * The following call to RemoveDisplay is to catch race conditions during
850      * shutdown. There is no point in starting a display if Dtlogin is in the
851      * process of shutting down...
852      */
853     if (d->displayType.origin == FromFile && dt_shutdown ) {
854         RemoveDisplay(d);
855         return;
856     }
857     
858     {
859       /* make a backup of the authFile before loading resources and       */
860       /* copy it back to authFile field od display structure for X server */
861       /* to reread the host database list on reset                          */
862       /* RK     11.22.93                                                    */
863       char bkup[50];
864
865       bkup[0] = '\0';
866       if (d->authFile)
867         strcpy(bkup ,d->authFile);
868
869       LoadDisplayResources (d);
870
871       /* The Xserver may NOT have been killed, so reuse the authFile.  */
872       if (NULL == d->authFile &&
873           0 < strlen(bkup) &&
874           0 == strncmp(authDir, bkup, strlen(authDir)))
875         d->authFile= (char *) strdup(bkup);
876
877       if (d->authFile == NULL) 
878         authFile_str = "NULL"; 
879       else
880         authFile_str = d->authFile;
881
882       Debug("(Mid StartDisplay) d->authfile %s; authDir %s; bkup %s\n",
883             authFile_str, authDir, bkup);
884     }
885
886     if (d->displayType.location == Local)
887     {
888         /* don't bother pinging local displays; we'll
889          * certainly notice when they exit
890          */
891         d->pingInterval = 0;
892         if (d->authorize)
893         {
894             Debug ("SetLocalAuthorization %s, auth %s\n",
895                     d->name, d->authNames);
896
897             SetLocalAuthorization (d);
898
899             /*
900              * reset the server after writing the authorization information
901              * to make it read the file (for compatibility with old
902              * servers which read auth file only on reset instead of
903              * at first connection)
904              */
905             if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
906                 kill (d->serverPid, d->resetSignal);
907         }
908
909 #ifndef __apollo
910         /*
911          *  initialize d->utmpId. Check to see if anyone else is using
912          *  the requested ID. Always allow the first request for "dt" to
913          *  succeed as utmp may have become corrupted.
914          */
915
916         if (d->utmpId == NULL) {
917             static int firsttime = 1;
918             static char letters[] = "0123456789abcdefghijklmnopqrstuvwxyzz";
919             char *t;        
920
921             d->utmpId = malloc(5);
922             strcpy(d->utmpId, UTMPREC_PREFIX);
923             d->utmpId[4] = '\0';
924             
925             t = letters;
926             
927             do {
928                 if ( firsttime || UtmpIdOpen(d->utmpId)) {
929                     firsttime = 0;
930                     break;
931                 }               
932                 else {
933                     strncpy(&(d->utmpId[strlen(d->utmpId)]), t++, 1);
934                 }
935             } while (*t != NULL);
936
937             if (*t == NULL) {
938                 Debug ("All DT utmp IDs already in use. Removing display %s\n",
939                         d->name);
940                 LogError ((unsigned char *)"All DT utmp IDs already in use. Removing display %s\n",
941                         d->name);
942                 RemoveDisplay(d);
943                 return;
944             }
945         }
946 #endif
947
948         /*
949          *  set d->gettyLine to "console" for display ":0" if it is not 
950          *  already set...
951          */
952
953         if (! d->gettyLine || strlen(d->gettyLine) == 0 ) {
954             char *p;
955             
956             if ( (p = index(d->name,':')) != NULL &&
957                  (  strncmp(++p,"0",1) == 0 )) {
958
959                 d->gettyLine  = (char *) malloc(8);
960                 strcpy(d->gettyLine,  "console");
961             }
962             else {
963                 d->gettyLine  = (char *) malloc(3);
964                 strcpy(d->gettyLine,  "??");
965             }
966         }
967
968
969         /*
970          *  if gettyLine is set to "console", set gettySpeed to "console" also
971          */
972                         
973         if (d->gettyLine && (strcmp(d->gettyLine, "console") == 0 ) ) {
974             if (d->gettySpeed) 
975                 free((char *) d->gettySpeed);
976
977             d->gettySpeed = (char *) malloc(8);
978             if (d->gettySpeed)
979                 strcpy(d->gettySpeed, "console");
980         }
981                     
982
983         /*
984          *  start server. If it cannot be started and this is the console,
985          *  run a getty...
986          */
987          
988         Debug("Attempting to start server for %s.  startTries = %d\n", 
989                 d->name, d->startTries);
990
991         if (d->serverPid == -1) {
992             static int bootup = 0;
993             
994             while (bootup++ < 5) {
995                 if (GettyRunning(d)) {
996                     GettyMessage(d,3);
997                     bootup = 5;
998                     break;
999                 }
1000                 else {
1001                     sleep(1);
1002                 }
1003             }
1004         }
1005         
1006         if (d->serverPid == -1 && 
1007             (d->startTries++ >= d->startAttempts ||
1008              !StartServer (d)))
1009         {
1010             LogError ((unsigned char *)"Server for display %s can't be started.\n", d->name);
1011
1012             d->serverPid = -1;
1013
1014             GettyMessage(d,4);
1015
1016             if (!StartGetty(d))
1017                 RemoveDisplay (d);
1018             return;
1019         }
1020     }
1021     else
1022     {
1023         /* this will only happen when using XDMCP */
1024         if (d->authorizations)
1025             SaveServerAuthorizations (d, d->authorizations, d->authNum);
1026
1027         /*
1028          *  Generate a utmp ID address for a foreign display. Use the last
1029          *  four characters of the DISPLAY name, shifting left if they
1030          *  are already in use...
1031          */
1032  
1033         if (d->utmpId == NULL) {
1034             int i;
1035             char *p, *q;
1036             struct utmp *u;
1037             
1038             d->utmpId = malloc(sizeof(u->ut_id) +1);
1039  
1040             i = strlen (d->name);
1041             if (i >= sizeof (u->ut_id))
1042                 i -= sizeof (u->ut_id);
1043             else
1044                 i = 0;
1045  
1046             for ( p = d->name, q = d->name + i; p <= q; q-- ) {
1047                 (void) strncpy (d->utmpId, q, sizeof (u->ut_id));
1048                 d->utmpId[sizeof(u->ut_id)] = '\0';
1049                 if (UtmpIdOpen(d->utmpId))
1050                     break;
1051             }
1052
1053 #ifdef DEF_NETWORK_DEV
1054             /*
1055              * If "networkDev" does not start with "/dev/" then foreign
1056              * accounting is turned off. Return utmpId to NULL.
1057              */
1058             if (networkDev && strncmp(networkDev,"/dev/",5) !=0 ) {
1059                 free(d->utmpId);
1060                 d->utmpId = NULL;
1061             }           
1062 #endif       
1063         }
1064     }
1065
1066     if (NULL == d->authFile)
1067       authFile_str = "NULL";
1068     else
1069       authFile_str = d->authFile;
1070
1071     Debug("(New StartDisplay) d->authfile %s; authDir %s\n",
1072           authFile_str, authDir);
1073
1074     /*
1075      *  make sure stderr is pointing to the current error log file...
1076      */
1077     SyncErrorFile(0);
1078
1079     
1080 #ifdef OSFDEBUG
1081     if (!nofork_session)
1082         pid = fork ();
1083     else
1084         pid = 0;
1085     switch (pid)
1086 #else
1087     switch (pid = fork ())
1088 #endif
1089     {
1090     case 0:
1091 #ifdef OSFDEBUG
1092         if (!nofork_session) {
1093             CleanUpChild ();
1094             signal (SIGPIPE, SIG_IGN);
1095         }
1096 #else
1097         CleanUpChild ();
1098         signal (SIGPIPE, SIG_IGN);
1099 #endif
1100
1101         /* 
1102          * set global display name for Debug()
1103          */
1104          
1105         {
1106             char *p, *s, *t;
1107             
1108             p = DisplayName;
1109             
1110             strncpy(p, d->name, sizeof(DisplayName));
1111             DisplayName[sizeof(DisplayName)-1] = '\0';
1112             
1113             if ( (s = strchr(p,':')) != NULL )
1114                 if ( (t = strchr(p,'.')) != NULL )
1115                     strcpy(t,s);
1116         }
1117
1118         
1119         SetAuthorization (d);
1120
1121         /*
1122          * do process accounting...
1123          */
1124
1125         {
1126             char *line = (d->displayType.location==Local) 
1127                 ? d->gettyLine : d->name;
1128 #ifdef DEF_NETWORK_DEV
1129             if (d->displayType.location != Local &&
1130                 networkDev && !strncmp(networkDev,"/dev/",5))
1131             {
1132                 char *devname;
1133                 int devexists;
1134                 struct stat devinfo;
1135                 devname = networkDev; /* networkDev resource */
1136
1137                 devexists = (lstat(devname,&devinfo)==0);
1138
1139                 if (!devexists && (MK_NETWORK_DEV(devname) < 0)) {
1140                     Debug("Creation of file '%s' failed:\n  %s (%d)\n",
1141                         devname,strerror(errno),errno);
1142                 } else {
1143
1144                     for (line=devname; *line; line++);
1145                     while (line>devname && *line!='/') line--;
1146                     if (*line=='/') line++;
1147
1148                     Debug("Using pseudo-tty %s; line=%s\n",
1149                         devname,line);
1150                 }
1151             }
1152 #endif
1153             Account(d, "LOGIN", line, getpid(), LOGIN_PROCESS, status);
1154         }
1155
1156         if (!WaitForServer (d))
1157             exit (OPENFAILED_DISPLAY);
1158
1159         /*
1160          * start the fallback console, if the display is local..
1161          * 
1162          * if the display is remote, fbconsole should be started on
1163          * remote host. 
1164          */
1165 #ifdef sun
1166         if (d->displayType.location==Local) {
1167             if (d->authFile && strlen(d->authFile) > 0 ) {
1168                 strcpy(buff, "XAUTHORITY=");
1169                 strcat(buff, d->authFile);
1170                 putenv(buff);
1171             }
1172             sprintf(start_fbconsole,"%s -d %s &",FBCONSOLE, d->name);
1173
1174             if(system(start_fbconsole) == -1)
1175                Debug("Failed to start the fallback console - %s\n",FBCONSOLE);
1176         }
1177 #endif
1178
1179         if (d->useChooser)
1180             RunChooser (d);
1181         else
1182             ManageSession (d);
1183         exit (REMANAGE_DISPLAY);
1184     case -1:
1185         break;
1186     default:
1187         Debug ("Child manager process started for %s. pid = %d\n", 
1188                 d->name, pid);
1189         d->pid = pid;
1190         d->status = running;
1191         break;
1192     }
1193 }
1194
1195 static void
1196 TerminateProcess(int pid, int sig )
1197 {
1198     kill (pid, sig);
1199 #ifdef SIGCONT
1200     kill (pid, SIGCONT);
1201 #endif
1202 }
1203
1204 /*
1205  * transition from running to zombie, suspended, or deleted
1206  */
1207
1208 void 
1209 StopDisplay( struct display *d )
1210 {
1211     waitType      status;
1212
1213     bzero(&status, sizeof(waitType));
1214     Debug("StopDisplay(): %s, server pid = %d, manager pid = %d, dt_shutdown = %d\n",
1215           d->name, d->serverPid, d->pid, dt_shutdown);
1216            
1217     if (d->serverPid != -1)
1218         /* don't remove the console */
1219         if ((d->displayType.location == Local) && !dt_shutdown ) 
1220             d->status = suspended;
1221         else
1222             d->status = zombie; /* be careful about race conditions */
1223
1224     if (d->pid != -1)
1225         TerminateProcess (d->pid, SIGTERM);
1226
1227     if (d->serverPid != -1) {
1228         TerminateProcess (d->serverPid, d->termSignal);
1229 #ifdef sun
1230         {
1231             int kbd_fd;
1232             int translate=TR_ASCII;
1233
1234             Debug ("Resetting keyboard\n");
1235
1236             if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) {
1237                 Debug("/dev/kbd open failed\n");
1238             } else if (ioctl(kbd_fd, KIOCTRANS, (caddr_t) &translate)) {
1239                 Debug("Could not set /dev/kbd back to ASCII mode\n");
1240             }
1241         }
1242 #endif
1243     }
1244     else 
1245         if ((d->displayType.location == Local) || !dt_shutdown ) {
1246             /* don't remove the console */
1247             Account(d, NULL, NULL, 0, DEAD_PROCESS, status);
1248             RemoveDisplay (d);
1249         }           
1250 }
1251
1252
1253 /*
1254  * transition from running to phoenix or notRunning
1255  */
1256
1257 static void 
1258 RestartDisplay( struct display *d, int forceReserver )
1259 {
1260     if (d->serverPid != -1 && (forceReserver || d->terminateServer))
1261     {
1262         TerminateProcess (d->serverPid, d->termSignal);
1263         d->status = phoenix;
1264     }
1265     else
1266     {
1267         d->status = notRunning;
1268     }
1269 }
1270
1271 static FD_TYPE  CloseMask;
1272 static int      max;
1273
1274 void
1275 RegisterCloseOnFork( int fd )
1276 {
1277     FD_SET (fd, &CloseMask);
1278     if (fd > max)
1279         max = fd;
1280 }
1281
1282 #if 0           /* utility routine: activate if needed...                  */
1283 int 
1284 CloseOnFork( void )
1285 {
1286     FD_CLR (fd, &CloseMask);
1287     if (fd == max) {
1288         while (--fd >= 0)
1289             if (FD_ISSET (fd, &CloseMask))
1290                 break;
1291         max = fd;
1292     }
1293 }
1294 #endif
1295
1296 CloseOnFork ()
1297 {
1298     int fd;
1299
1300     for (fd = 0; fd <= max; fd++)
1301         if (FD_ISSET (fd, &CloseMask))
1302             close (fd);
1303     FD_ZERO (&CloseMask);
1304     max = 0;
1305 }
1306
1307 static int  pidFd;
1308 static FILE *pidFilePtr;
1309
1310 static long 
1311 StorePid( void )
1312 {
1313     long        oldpid;
1314
1315     if (pidFile && pidFile[0] != '\0') {
1316         pidFd = open (pidFile, 2);
1317         if (pidFd == -1 && errno == ENOENT)
1318         {
1319             /*
1320              * HP OSF/1 will not allow an fdopen 
1321              * of a file descriptor handed back by creat(2).
1322              *  The workaround is to close the created file, and 
1323              * open it Read/Write.  This will be transparent to HP-UX.
1324              */
1325             pidFd = creat (pidFile, 0644);
1326             close( pidFd );
1327             pidFd = open (pidFile, 2);
1328         }
1329         if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+")))
1330         {
1331             LogError ((unsigned char *)"Process ID file %s cannot be opened\n",
1332                       pidFile);
1333             return -1;
1334         }
1335         if (fscanf (pidFilePtr, "%ld", &oldpid) != 1)
1336             oldpid = -1;
1337         fseek (pidFilePtr, 0l, 0);
1338         if (lockPidFile)
1339         {
1340 #if defined (SYSV) || defined (SVR4)
1341             if (lockf (pidFd, F_TLOCK, 0) == -1)
1342             {
1343                 if ((errno == EAGAIN) || (errno == EACCES))
1344                     return oldpid;
1345                 else
1346                     return -1;
1347             }
1348 #else
1349             if (flock (pidFd, LOCK_EX|LOCK_NB) == -1)
1350             {
1351                 if (errno == EWOULDBLOCK)
1352                     return oldpid;
1353                 else
1354                     return -1;
1355             }
1356 #endif
1357         }
1358
1359         /*
1360          * HPUX releases the lock on ANY close of the file, not just the
1361          * one that established the lock. -prr
1362          */
1363         /*      close(creat(pidFile, 0644)); */
1364
1365         (void) creat(pidFile, 0644);
1366         fprintf (pidFilePtr, "%ld\n", (long)getpid ());
1367         (void) fflush(pidFilePtr);
1368         RegisterCloseOnFork(pidFd);
1369     }
1370     return 0;
1371 }
1372
1373 static void
1374 UnlockPidFile( void )
1375 {
1376     if (lockPidFile)
1377 #if defined (SYSV) || defined (SVR4)
1378         lockf (pidFd, F_ULOCK, 0);
1379 #else
1380         flock (pidFd, LOCK_UN);
1381 #endif
1382     close (pidFd);
1383     fclose (pidFilePtr);
1384 }
1385
1386 #ifdef oldcode
1387 /*VARARGS*/
1388 SetTitle (va_alist)
1389 va_dcl
1390 {
1391 #ifndef NOXDMTITLE
1392     char        *p = Title;
1393     int         left = TitleLen;
1394     char        *s;
1395     va_list     args;
1396
1397     va_start(args);
1398     *p++ = '-';
1399     --left;
1400     while (s = va_arg (args, char *))
1401     {
1402         while (*s && left > 0)
1403         {
1404             *p++ = *s++;
1405             left--;
1406         }
1407     }
1408     while (left > 0)
1409     {
1410         *p++ = ' ';
1411         --left;
1412     }
1413     va_end(args);
1414 #endif  
1415 }
1416 #endif
1417
1418 int 
1419 SetTitle( char *name, char *ptr )
1420 {
1421 #ifndef NOXDMTITLE
1422     char        *p, *s, *t;
1423     int         length;
1424
1425
1426     /*
1427      *  remove domain qualifiers and screens from name...
1428      */
1429
1430     if ( (p = malloc(strlen(name) + 1)) == NULL) return;
1431     strcpy(p, name);
1432
1433     if ( (s = strchr(p,':')) == NULL ) {
1434         free(p);
1435         return;
1436     }
1437     
1438     if ( (t = strchr(s,'.')) != NULL )
1439         *t = '\0';
1440
1441     if ( (t = strchr(p,'.')) != NULL )
1442         strcpy(t,s);
1443     
1444     /*
1445      *  if there is enough room shift program name to left,
1446      *  then append display name in remaining space.
1447      */
1448
1449     s = Title;
1450     length = strlen(s);
1451     
1452     t = strrchr(s, '/');
1453     if ( (t != NULL) && ((t-s+1) >= (strlen(p) + 3)) ) {
1454         t++;
1455
1456         strcpy(s,t);            /* "program"                       */
1457         strcat(s," <");         /* "program <"                     */
1458         strcat(s,p);            /* "program <displayName"          */
1459         strcat(s,">");          /* "program <displayName>"         */
1460
1461         t = s + strlen(s);
1462         length = length - strlen(s);
1463         while (length > 0){
1464             *t++ = ' ';
1465             length--;
1466         }
1467     }
1468
1469     free(p);
1470 #endif
1471 }
1472
1473
1474 /*****************************************************************************
1475 *    StartGetty
1476 *    
1477 *    Start a "getty" running on the console...
1478 *
1479 *****************************************************************************/
1480
1481 #if defined (_AIX) && defined (_POWER) || defined (__osf__)
1482 #define GETTYPATH "/usr/sbin/getty"
1483 #elif !defined (__apollo)
1484 #define GETTYPATH "/etc/getty"
1485 #endif
1486
1487 static int 
1488 StartGetty( struct display *d )
1489 {
1490     int         pid;
1491     char tynm[20];
1492     waitType  status;
1493
1494     Debug ("StartGetty(): %s\n", d->name);
1495
1496     bzero(&status, sizeof(waitType));
1497     /*
1498      * ensure that server is known dead...
1499      */
1500
1501     d->serverPid = -1;
1502
1503 #if !defined(GETTYPATH)
1504     return FALSE;
1505 #else
1506
1507     /*
1508      * check to see if we have a valid device (at least a non-null name)...
1509      */
1510
1511     if ( d->gettyLine                   && 
1512         (strlen(d->gettyLine) > 0)      &&
1513         (strcmp(d->gettyLine,"??") != 0)        )
1514         ;
1515     else
1516         return FALSE;
1517
1518
1519     /*
1520      * if there is already a getty running on the device, set up
1521      * to start watching it. When it exits, restart the server...
1522      */
1523
1524     if ( GettyRunning(d) ) {
1525         d->status = suspended;          /* set up to restart server        */
1526         wakeupTime = 0;                 /* enable polling                  */
1527
1528         sleep(1);                       /* wait for fbconsole to go away   */
1529         GettyMessage(d,1);              /* print a help message            */
1530
1531         return TRUE;
1532     }
1533
1534     
1535     /*
1536      * there is no getty running on the device, try to start one...
1537      */
1538
1539     d->status = phoenix;                /* set up to restart server        */
1540     d->startTries = 0;
1541     
1542     switch (pid = fork ()) {
1543     case 0:
1544         CleanUpChild ();
1545
1546         /*
1547          *  do process accounting...
1548          */
1549         Account(d, "LOGIN", NULL, getpid(), LOGIN_PROCESS, status);
1550
1551
1552         #ifdef _AIX
1553         /* The tty argument for getty on AIX must be of the form "/dev/any tty"
1554            and so the following logic
1555            Raghu krovvidi 07.07.93
1556          */
1557          strcpy(tynm,"/dev/");
1558          strcat(tynm,d->gettyLine); 
1559         #else
1560          strcpy(tynm, d->gettyLine);
1561         #endif
1562
1563         Debug(" execing getty on %s\n",tynm);
1564         execl(GETTYPATH, "getty", tynm, d->gettySpeed, (char *)0);
1565         LogError ((unsigned char *)"Can not execute %s for %s: errno = %d\n",
1566                    GETTYPATH, d->name, errno);
1567
1568         exit (UNMANAGE_DISPLAY);
1569
1570     case -1:
1571         Debug ("Fork of /etc/getty failed %s\n", d->name);
1572         LogError ((unsigned char *)"Can not fork to execute /etc/getty %s\n", d->name);
1573         return FALSE;
1574
1575     default:
1576         break;
1577     }
1578
1579     Debug ("/etc/getty started on %s\n", d->name);
1580     d->serverPid = pid;
1581     return TRUE;
1582 #endif /* GETTYPATH not defined */
1583 }
1584
1585  
1586 /***************************************************************************
1587  *
1588  *  GettyMessage
1589  *
1590  *  Print a message on the display device when going into No Windows mode.
1591  *
1592  ***************************************************************************/
1593
1594 void
1595 GettyMessage( struct display *d, int msgnum )
1596 {
1597     FILE *tf;
1598     char buf[128];
1599
1600     strcpy(buf,"/dev/");
1601     strcat(buf,d->gettyLine);
1602     
1603     if ( (tf = fopen (buf, "a")) != NULL) {
1604         fprintf (tf, 
1605           "\r\n\r\n*****************************************************************************\r\n*\r\n");
1606
1607         switch (msgnum) {
1608         case 1:
1609         
1610           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS1_LABEL,MC_DEF_SUS1_LABEL));
1611
1612           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS2_LABEL,MC_DEF_SUS2_LABEL));
1613
1614           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS3_LABEL,MC_DEF_SUS3_LABEL));
1615
1616           break;
1617           
1618         case 2:
1619         
1620           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_RES_LABEL,MC_DEF_RES_LABEL));
1621
1622           break;
1623           
1624         case 3:
1625         
1626           fprintf(tf,
1627                 (char *)ReadCatalog(MC_LABEL_SET,MC_START_LBLDPY,MC_DEF_START_LBLDPY),
1628                 d->name);
1629
1630           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_WAIT_LABEL,MC_DEF_WAIT_LABEL));
1631
1632           break;
1633           
1634         case 4:
1635         
1636           fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_X_LABEL,MC_DEF_X_LABEL),
1637                 d->name);
1638
1639           break;
1640
1641         }
1642         
1643         fprintf (tf, 
1644           "*****************************************************************************\r\n");
1645
1646
1647         fclose (tf);
1648     }
1649 }
1650
1651
1652 /***************************************************************************
1653  *
1654  *  GettyRunning
1655  *
1656  *  See if a getty process is running against the display device. This
1657  *  routine may need to be rewritten on other platforms if a different
1658  *  mechanism is needed to make the determination.
1659  *
1660  *  Output:  TRUE  == a login process is active on the requested device
1661  *           FALSE == a login process is not active on the device.
1662  *
1663  *  Sets d->gettyState:
1664  *    NONE - no getty running or don't care
1665  *    LOGIN - getty running
1666  *    USER - user logged in on getty
1667  *
1668  *  Note: The check for a getty process running is made by scanning
1669  *        /etc/utmp, looking for a login process on the respective device.
1670  *        However, the child Dtlogin spawned by the master Dtlogin to
1671  *        handle this display also is a "login process" according to
1672  *        /etc/utmp.  It provides a login path and therefore must register
1673  *        itself as so.  If a getty is also running, there are actually two
1674  *        login processes running against the same device at the same time.
1675  *
1676  *        The child Dtlogin dies before the scan of /etc/utmp is made.
1677  *        Provided /etc/utmp is updated correctly, the Dtlogin entry will
1678  *        be marked as dead and will not show up in the scan of /etc/utmp.
1679  ***************************************************************************/
1680
1681 int 
1682 GettyRunning( struct display *d )
1683 {
1684     struct utmp utmp;           /* local struct for new entry              */
1685     struct utmp *u;             /* pointer to entry in utmp file           */
1686     
1687     int         rvalue;         /* return value (TRUE or FALSE)            */
1688     char        buf[32];
1689         
1690     d->gettyState = DM_GETTY_NONE;
1691
1692     /*
1693      * check to see if we have a valid device (at least a non-null name)...
1694      */
1695
1696     if ( d->gettyLine                   && 
1697         (strlen(d->gettyLine) > 0)      &&
1698         (strcmp(d->gettyLine,"??") != 0)        )
1699         ;
1700     else
1701         return FALSE;
1702
1703
1704     bzero(&utmp, sizeof(struct utmp));
1705
1706 #ifdef _AIX
1707    if (!strcmp(d->gettyLine,"console")) {
1708         char *ttynm;
1709         int fd=0;
1710
1711         fd = open("/dev/console",O_RDONLY);
1712         ttynm = ttyname(fd);
1713         ttynm += 5;
1714         strcpy(utmp.ut_line,ttynm);
1715         close(fd);
1716     }
1717     else
1718         strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1719
1720 #else
1721     strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1722 #endif
1723     
1724     Debug("Checking for a getty on line %s.\n", utmp.ut_line);
1725     
1726     setutent();
1727
1728     rvalue = FALSE;
1729     
1730     while ( (u = getutent()) != NULL ) {
1731     
1732         if ((strncmp(u->ut_line, utmp.ut_line, sizeof(u->ut_line)) != 0) ||
1733             (strncmp(u->ut_id,   d->utmpId,    sizeof(u->ut_id))   == 0) )
1734             continue;
1735
1736         switch (u->ut_type) {
1737     
1738         case INIT_PROCESS:      strcpy(buf, "INIT_PROCESS");    break;
1739         case LOGIN_PROCESS:     strcpy(buf, "LOGIN_PROCESS");   break;
1740         case USER_PROCESS:      strcpy(buf, "USER_PROCESS");    break;
1741         case DEAD_PROCESS:      strcpy(buf, "DEAD_PROCESS");    break;
1742         default:                strcpy(buf, "UNKNOWN");         break;
1743         }
1744
1745         Debug("Utmp info: id=%.4s, user=%s, line=%s, pid=%d, type=%s\n",
1746                u->ut_id, u->ut_user, u->ut_line, u->ut_pid, buf);
1747
1748         if ( u->ut_type == INIT_PROCESS || u->ut_type == LOGIN_PROCESS) {
1749           d->gettyState = DM_GETTY_LOGIN;
1750         }
1751         else if (wakeupTime <= 0 && u->ut_type == USER_PROCESS) {
1752           d->gettyState = DM_GETTY_USER;
1753         }
1754      
1755         if (d->gettyState != DM_GETTY_NONE)
1756         {
1757             rvalue = TRUE;
1758             break;
1759         }
1760     }
1761
1762     endutent();
1763     return rvalue;
1764 }
1765
1766
1767  
1768 /***************************************************************************
1769  *
1770  *  CheckRestartTime
1771  *
1772  *  Check if enough time has elapsed since shutdown. 
1773  *
1774  *  This is primarily to work with /etc/shutdown.  When shutdown kills
1775  *  dtlogin (/etc/killall), init immediately restarts it.  Shutdown kills
1776  *  it again and init restarts it.  At each restart, the X-server may start
1777  *  on the local display and then subsequently be killed.  The user sees a
1778  *  flashing screen and sometimes the console is left in an unreset state.
1779  *
1780  *  When Dtlogin shuts down, it touches the access time on the Xservers
1781  *  file.  (MarkShutdownTime()).  This time is then used to determine if
1782  *  sufficient time has elapsed before restarting.
1783  *
1784  ***************************************************************************/
1785
1786 static void
1787 CheckRestartTime( void )
1788 {
1789     struct stat statb;
1790     int         sleeptime;
1791     
1792     if (servers[0] == '/' && stat(servers, &statb) != -1) {
1793
1794         Debug("Checking restart time.\n");
1795         
1796 #ifdef OSFDEBUG
1797 /* only those other systems are this slow :-) */
1798         sleeptime = 6 - (int) (time((time_t *) 0) - statb.st_atime);
1799 #else
1800         sleeptime = 30 - (int) (time((time_t *) 0) - statb.st_atime);
1801 #endif
1802         
1803         if ( sleeptime > 30 ) sleeptime = 30;
1804         
1805         if ( sleeptime > 0 ) {
1806             Debug("Restarting too soon after shutdown. Sleeping %d seconds.\n",
1807                    sleeptime);
1808             sleep (sleeptime);
1809         }
1810     }
1811
1812 }
1813
1814  
1815 /***************************************************************************
1816  *
1817  *  MarkShutdownTime
1818  *
1819  *  Save the time when we shut down to check later for too fast of a restart.
1820  *
1821  ***************************************************************************/
1822
1823 static void
1824 MarkShutdownTime( void )
1825 {
1826     struct stat statb;
1827     struct utimbuf timebuf;
1828     
1829     if (servers[0] == '/' && stat(servers, &statb) != -1) {
1830
1831         Debug("Marking shutdown time.\n");
1832
1833         timebuf.actime = time((time_t *) 0 );
1834         timebuf.modtime = statb.st_mtime;
1835
1836         if ( (utime(servers, &timebuf)) != 0 ) {
1837             Debug("MarkShutdownTime(): utime() error = %d\n", errno);
1838         }
1839     }
1840 }
1841
1842
1843 /***************************************************************************
1844  *
1845  *  dtMakeDefaultDir
1846  *
1847  * Make the default dt directory "/var/dt" if needed.
1848  *
1849  ***************************************************************************/
1850 static void
1851 dtMakeDefaultDir( void )
1852 {
1853     dtmkdir("/var", 0775);
1854     dtmkdir("/var/dt", 0755);
1855     dtmkdir("/var/dt/tmp", 0755);
1856     dtmkdir("/var/dt/appconfig", 0755);
1857     dtmkdir("/var/dt/appconfig/appmanager", 0755);
1858 }
1859
1860 static void
1861 dtmkdir(char *dir, mode_t dir_mode)
1862 {
1863     struct stat file_status;
1864
1865     if ( stat(dir, &file_status) != 0) {
1866         /** try to create it **/
1867         if ( mkdir(dir, dir_mode) == 0) {
1868             chmod(dir, dir_mode);  /** since umask is non-zero **/
1869             Debug("Created dir %s\n", dir);
1870         } else {
1871             LogError((unsigned char *)"Unable to create dir %s\n", dir);
1872         }
1873     } else {
1874         if ( (file_status.st_mode & dir_mode) != dir_mode) {
1875             /** try to set correct permissions **/
1876             if ( chmod(dir, file_status.st_mode | dir_mode) == 0) {
1877                 Debug("Set permissions on %s\n", dir);
1878             } else {
1879                 LogError((unsigned char *)
1880                          "Unable to set permissions on %s\n", dir);
1881             }
1882         }
1883     }
1884 }