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