2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* (c) Copyright 1997 The Open Group */
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. *
31 * xdm - display manager daemon
33 * $TOG: dm.c /main/18 1999/01/19 17:44:08 mgreess $
35 * Copyright 1988 Massachusetts Institute of Technology
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.
47 * Author: Keith Packard, MIT X Consortium
54 # include <sys/signal.h>
55 # include <sys/stat.h>
62 #if defined (SYSV) || defined (SVR4)
76 #define sigmask(m) (1 << (( m-1)))
80 /***************************************************************************
82 * External variable declarations
84 ***************************************************************************/
86 #if defined(USL) || defined(__uxp__)
87 extern int makepttypair ();
91 /***************************************************************************
93 * Local procedure declarations
95 ***************************************************************************/
97 static void CheckDisplayStatus( struct display *d) ;
98 static void CheckRestartTime( void ) ;
99 static void ChildNotify( int arg ) ;
100 static void MarkDisplay( struct display *d) ;
101 static void KillDisplay( struct display *d) ;
102 static void MarkShutdownTime( void ) ;
103 static void ProcessChildDeath( int pid, waitType status) ;
104 static void RescanIfMod( void ) ;
105 static void RescanNotify( int arg ) ;
106 static void RescanServers( void ) ;
107 static void RestartDisplay( struct display *d, int forceReserver) ;
108 static int ScanServers( void ) ;
109 static void SetAccessFileTime( void ) ;
110 static void SetConfigFileTime( void ) ;
111 static int StartGetty( struct display *d) ;
112 static void StopAll( int arg ) ;
113 static long StorePid( void ) ;
114 static void TerminateProcess( int pid, int sig) ;
115 static void UnlockPidFile( void ) ;
116 static void dtMakeDefaultDir( void );
117 static void dtmkdir(char *dir, mode_t dir_mode);
122 /***************************************************************************
126 ***************************************************************************/
127 struct passwd puser; /* pseudo-user password entry */
130 static long ServersModTime, ConfigModTime, AccessFileModTime;
134 char DisplayName[32]="main";
137 int nofork_session = 0;
141 char *Title; /* Global argv[0] */
145 static int parent_pid = -1; /* PID of parent dtlogin process */
148 /***************************************************************************/
151 main( int argc, char **argv )
155 struct passwd *p; /* pointer to passwd structure (pwd.h) */
158 * make sure at least world write access is disabled...
160 if ( (oldumask = umask(022) & 002) == 002)
161 (void) umask(oldumask);
165 TitleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - Title;
170 * save program name and path...
173 if ( (progName = malloc(strlen(argv[0]) + 1)) != NULL )
174 strcpy(progName, argv[0]);
176 #if defined(USL) || defined(__uxp__)
177 /* create master slave pair for use in login */
178 if (makepttypair () < 0)
180 Debug ("Could not create pty for use in login");
187 * Step 1 - load configuration parameters
189 InitResources (argc, argv);
190 SetConfigFileTime ();
193 * Only allow root to run xdm to avoid problems (HP 700/X version)
195 if (debugLevel == 0 && getuid() != 0)
198 (char *)ReadCatalog(MC_ERROR_SET,MC_BAD_ROOT,MC_DEF_BAD_ROOT),
203 dtMakeDefaultDir(); /** Create /var/dt if needed **/
204 CheckErrorFile(); /** verify that we can open an error log **/
207 if (debugLevel >= 10)
211 if (debugLevel == 0 && daemonMode)
213 if ( (oldpid = StorePid ()) != 0 )
215 if (oldpid == (long) -1)
217 ReadCatalog(MC_LOG_SET,MC_LOG_NO_CREATE,MC_DEF_LOG_NO_CREATE),
220 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_LOCK,MC_DEF_LOG_NO_LOCK),
226 * Check if we are restarting too fast...
233 * Initialize error file, open XDMCP socket, and set up interrupt handlers.
238 CreateWellKnownSockets ();
239 parent_pid = getpid(); /* PID of parent dtlogin process */
240 (void) signal (SIGTERM, StopAll);
241 (void) signal (SIGINT, StopAll);
244 * Set pseudo-user to "nobody". Xserver will be run as that pseudo-user
245 * rather than root (unless pseudo user is specifically set to another
246 * user via the Xservers file).
249 if ( (p = getpwnam ("nobody")) != NULL) {
253 * This should not happen, the "nobody" user should always be present.
254 * If it does, fall back to traditional values of the "root" user
263 * Ensure the interrupt handlers are set. The Passwd Etc. libraries
264 * (getpwnam()) disable SIGTERM and SIGINT.
267 (void) signal (SIGTERM, StopAll);
268 (void) signal (SIGINT, StopAll);
274 * Step 2 - Read /etc/Xservers and set up
277 * Keep a sub-daemon running
280 SetAccessFileTime ();
281 ScanAccessDatabase ();
282 #if !defined (ENABLE_DYNAMIC_LANGLIST)
284 #endif /* ENABLE_DYNAMIC_LANGLIST */
287 (void) signal (SIGHUP, RescanNotify);
288 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__uxp__)|| defined (__osf__) || defined(linux)
289 (void) signal (SIGCHLD, ChildNotify);
291 while (AnyWellKnownSockets() || AnyDisplaysLeft ())
301 #if defined(SYSV) && !defined(hpux) && !defined(_AIX) && !defined(__uxp__) && !defined (__osf__) && !defined(linux)
309 Debug ("Nothing left to do, exiting\n");
313 RescanNotify( int arg )
315 Debug ("Caught SIGHUP\n");
317 #if defined(SYSV) || defined(SVR4)
318 signal (SIGHUP, RescanNotify);
329 static DisplayType acceptableTypes[] =
330 { { Local, Permanent, FromFile },
331 { Foreign, Permanent, FromFile },
334 #define NumTypes (sizeof (acceptableTypes) / sizeof (acceptableTypes[0]))
336 if (servers[0] == '/')
338 serversFile = fopen (servers, "r");
339 if (serversFile == NULL)
342 ReadCatalog(MC_LOG_SET,MC_LOG_NO_SRVACC,MC_DEF_LOG_NO_SRVACC),
346 if (ServersModTime == 0)
348 fstat (fileno (serversFile), &statb);
349 ServersModTime = statb.st_mtime;
351 while (fgets (lineBuf, sizeof (lineBuf)-1, serversFile))
353 len = strlen (lineBuf);
354 if (lineBuf[len-1] == '\n')
355 lineBuf[len-1] = '\0';
356 ParseDisplay (lineBuf, acceptableTypes, NumTypes, &puser);
358 fclose (serversFile);
362 ParseDisplay (servers, acceptableTypes, NumTypes, &puser);
367 MarkDisplay( struct display *d )
369 d->state = MissingEntry;
373 KillDisplay( struct display *d )
376 Debug("Sending HUP to display %s\n", d->name);
378 Debug("Sending HUP to display ?\n");
380 kill(d->pid, SIGHUP);
384 RescanServers( void )
386 Debug ("Rescanning servers\n");
388 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_REBUILD,MC_DEF_LOG_REBUILD),
390 #if !defined (ENABLE_DYNAMIC_LANGLIST)
392 #endif /* ENABLE_DYNAMIC_LANGLIST */
394 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_RESCAN,MC_DEF_LOG_RESCAN));
395 ForEachDisplay (MarkDisplay);
396 ForEachDisplay (KillDisplay);
400 SetAccessFileTime ();
401 ScanAccessDatabase ();
406 SetConfigFileTime( void )
410 if (stat (config, &statb) != -1)
411 ConfigModTime = statb.st_mtime;
416 SetAccessFileTime( void )
420 if (stat (accessFile, &statb) != -1)
421 AccessFileModTime = statb.st_mtime;
430 if (stat (config, &statb) != -1)
432 if (statb.st_mtime != ConfigModTime)
434 Debug ("Config file %s has changed, rereading\n", config);
436 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADCFG,MC_DEF_LOG_REREADCFG),
438 ConfigModTime = statb.st_mtime;
443 if (servers[0] == '/' && stat(servers, &statb) != -1)
445 if (statb.st_mtime != ServersModTime)
447 Debug ("Servers file %s has changed, rescanning\n", servers);
449 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADSRV,MC_DEF_LOG_REREADSRV),
451 ServersModTime = statb.st_mtime;
452 ForEachDisplay (MarkDisplay);
457 if (accessFile && accessFile[0] && stat (accessFile, &statb) != -1)
459 if (statb.st_mtime != AccessFileModTime)
461 Debug ("Access file %s has changed, rereading\n", accessFile);
463 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADACC,MC_DEF_LOG_REREADACC),
465 AccessFileModTime = statb.st_mtime;
466 ScanAccessDatabase ();
473 * catch a SIGTERM, kill all displays and exit
476 static int dt_shutdown = 0;
481 if (parent_pid != getpid())
484 * we got caught in a race condition - we are really a
485 * child dtlogin process that has been killed by the parent
486 * dtlogin process before we got a chance to return from
487 * fork() and remove this signal handler
489 Debug ("Child dtlogin caught signal %d before it could become a real child\n", arg);
490 (void) signal (arg, SIG_DFL); /* ensure no more handler */
491 TerminateProcess (getpid(), arg); /* and send signal again */
495 Debug ("Shutting down entire manager\n");
496 DestroyWellKnownSockets ();
499 ForEachDisplay (StopDisplay);
500 #if defined(SYSV) || defined(SVR4)
501 /* to avoid another one from killing us unceremoniously */
502 (void) signal (SIGTERM, StopAll);
503 (void) signal (SIGINT, StopAll);
508 * notice that a child has died and may need another
514 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__uxp__) || defined (__osf__) || defined(linux)
516 ChildNotify( int arg )
524 In HP-UX, SIGCHLDs are queued rather than lost if we are in the middle
525 of processing one (see SIGNAL(5), WARNINGS). The following code relies
528 If we have a socket, then we are using "select" to block
529 (WaitForSomething) rather than "wait". If a child dies, ChildReady is
530 set and the select unblocks. We then loop, processing the child that
531 died plus any that die while we are processing others. Finally we
532 activate the signal handler again and go around one more time in case a
533 child died right before activating the signal handler.
543 #if defined(SYSV) || defined(SVR4) || defined(hpux)
545 if (AnyWellKnownSockets()) {
546 while ( ChildReady ) {
548 while ((pid = waitpid((pid_t) -1, &status, WNOHANG)) > 0 )
550 while ((pid = wait3 (&status, WNOHANG, NULL)) > 0 )
552 ProcessChildDeath(pid, status);
555 (void) signal (SIGCHLD, ChildNotify);
560 /* XXX classic sysV signal race condition here with RescanNotify */
561 if ((pid = wait (&status)) != -1)
562 ProcessChildDeath(pid, status);
566 mask = sigblock (sigmask (SIGCHLD) | sigmask (SIGHUP));
567 Debug ("Signals blocked, mask was 0x%x\n", mask);
568 if (!ChildReady && !Rescan)
573 while ((pid = wait3 (&status, WNOHANG, (struct rusage *) 0)) > 0)
574 ProcessChildDeath(pid, status);
582 ProcessChildDeath( int pid, waitType status )
587 Debug ("Processing child death, pid = %d\n", pid);
591 if ( (d = FindDisplayByPid (pid)) != 0 ) {
595 * do process accounting...
598 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
602 * make sure authorization file is deleted...
606 if (d->authorization && d->authFile) {
607 (void) unlink (d->authFile);
615 * reset "startTries" ...
617 * Local displays: Only for clean exits of the server
618 * Foreign displays: Always except for OPENFAILED_DISPLAY
620 * Note: if startTries expires and a "getty" is run on the local
621 * display, startTries will be reset to zero before
622 * attempting to restart the server.
625 switch (waitVal (status)) {
626 case OBEYSESS_DISPLAY:
627 case RESERVER_DISPLAY:
631 case OPENFAILED_DISPLAY:
635 if (d->displayType.location != Local )
644 * process exit status...
647 switch (waitVal (status)) {
648 case UNMANAGE_DISPLAY:
649 Debug ("Display exited with UNMANAGE_DISPLAY\n");
653 case OBEYSESS_DISPLAY:
654 Debug ("Display exited with (check)OBEYSESS_DISPLAY\n");
655 if (d->displayType.lifetime != Permanent || d->status == zombie)
658 RestartDisplay (d, FALSE);
662 Debug ("Display exited with unknown status %d\n", waitVal(status));
663 LogError ((unsigned char *)"Unknown session exit code %d from process %d\n",
664 waitVal (status), pid);
668 case OPENFAILED_DISPLAY:
669 Debug ("Display exited with OPENFAILED_DISPLAY\n");
670 if (d->displayType.origin == FromXDMCP)
671 SendFailed (d, "Cannot open display");
673 if (d->displayType.location != Local)
676 if (d->displayType.origin == FromXDMCP ||
677 d->status == zombie ||
678 d->startTries >= d->startAttempts)
681 RestartDisplay (d, TRUE);
685 case RESERVER_DISPLAY:
686 Debug ("Display exited with RESERVER_DISPLAY\n");
687 if (d->displayType.origin == FromXDMCP || d->status == zombie)
690 RestartDisplay (d, TRUE);
693 case waitCompose (SIGTERM,0,0):
694 Debug ("Display exited on SIGTERM\n");
695 if (d->displayType.origin == FromXDMCP || d->status == zombie)
698 RestartDisplay (d, TRUE);
701 case REMANAGE_DISPLAY:
702 Debug ("Display exited with REMANAGE_DISPLAY\n");
704 * XDMCP will restart the session if the display
707 if (d->displayType.origin == FromXDMCP || d->status == zombie)
710 RestartDisplay (d, FALSE);
713 case SUSPEND_DISPLAY:
714 Debug ("Display exited with SUSPEND_DISPLAY\n");
715 if (d->displayType.location == Local)
718 RestartDisplay (d, FALSE);
723 else if ( (d = FindDisplayByServerPid (pid)) != 0 )
728 * do process accounting...
731 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
736 Debug ("Zombie server reaped, removing display %s\n", d->name);
740 Debug ("Phoenix server arises, restarting display %s\n", d->name);
741 d->status = notRunning;
744 Debug ("Server for display %s terminated unexpectedly, status %d\n", d->name, waitVal (status));
745 LogError ((unsigned char *)"Server for display %s terminated unexpectedly %d\n",
746 d->name, waitVal(status) );
749 Debug ("Terminating session pid %d\n", d->pid);
750 TerminateProcess (d->pid, SIGTERM);
754 Debug ("Server exited for notRunning session on display %s\n", d->name);
757 Debug ("Server for display %s is suspended\n", d->name);
759 d->status = notRunning;
765 Debug ("Unknown child termination, status %d\n", waitVal (status));
770 CheckDisplayStatus( struct display *d )
773 if (d->displayType.origin == FromFile)
784 Debug("Check %s: status=%d wakeupTime=%d\n", d->name,
785 d->status, wakeupTime);
786 if (d->status == suspended && wakeupTime >= 0)
787 if ( GettyRunning(d) || (strcmp(d->gettyLine,"??") == 0))
788 if ( wakeupTime == 0 ) {
789 Debug("Polling of suspended server %s started.\n",
792 wakeupTime = (wakeupInterval < 10
794 : 2 * wakeupInterval );
797 Debug("Polling of suspended server %s stopped.\n",
799 wakeupTime = -1; /* disable polling */
800 d->status = notRunning; /* restart server */
802 if ( !dt_shutdown ) GettyMessage(d,2);
805 Debug("Polling of suspended server %s continued.\n",
807 wakeupTime = wakeupInterval; /* continue polling*/
810 if (d->status == notRunning)
818 StartDisplays( void )
820 ForEachDisplay (CheckDisplayStatus);
830 char start_fbconsole[1024];
833 Debug ("StartDisplay(): %s\n", d->name);
835 bzero(&status, sizeof(waitType));
836 if (d->authFile == NULL)
837 authFile_str = "NULL";
839 authFile_str = d->authFile;
841 Debug("(Old StartDisplay) d->authfile %s; authDir %s\n",
842 authFile_str, authDir);
845 * The following call to RemoveDisplay is to catch race conditions during
846 * shutdown. There is no point in starting a display if Dtlogin is in the
847 * process of shutting down...
849 if (d->displayType.origin == FromFile && dt_shutdown ) {
855 /* make a backup of the authFile before loading resources and */
856 /* copy it back to authFile field od display structure for X server */
857 /* to reread the host database list on reset */
863 strcpy(bkup ,d->authFile);
865 LoadDisplayResources (d);
867 /* The Xserver may NOT have been killed, so reuse the authFile. */
868 if (NULL == d->authFile &&
870 0 == strncmp(authDir, bkup, strlen(authDir)))
871 d->authFile= (char *) strdup(bkup);
873 if (d->authFile == NULL)
874 authFile_str = "NULL";
876 authFile_str = d->authFile;
878 Debug("(Mid StartDisplay) d->authfile %s; authDir %s; bkup %s\n",
879 authFile_str, authDir, bkup);
882 if (d->displayType.location == Local)
884 /* don't bother pinging local displays; we'll
885 * certainly notice when they exit
890 Debug ("SetLocalAuthorization %s, auth %s\n",
891 d->name, d->authNames);
893 SetLocalAuthorization (d);
896 * reset the server after writing the authorization information
897 * to make it read the file (for compatibility with old
898 * servers which read auth file only on reset instead of
899 * at first connection)
901 if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
902 kill (d->serverPid, d->resetSignal);
907 * initialize d->utmpId. Check to see if anyone else is using
908 * the requested ID. Always allow the first request for "dt" to
909 * succeed as utmp may have become corrupted.
912 if (d->utmpId == NULL) {
913 static int firsttime = 1;
914 static char letters[] = "0123456789abcdefghijklmnopqrstuvwxyzz";
917 d->utmpId = malloc(5);
918 strcpy(d->utmpId, UTMPREC_PREFIX);
924 if ( firsttime || UtmpIdOpen(d->utmpId)) {
929 strncpy(&(d->utmpId[strlen(d->utmpId)]), t++, 1);
931 } while (*t != NULL);
934 Debug ("All DT utmp IDs already in use. Removing display %s\n",
936 LogError ((unsigned char *)"All DT utmp IDs already in use. Removing display %s\n",
945 * set d->gettyLine to "console" for display ":0" if it is not
949 if (! d->gettyLine || strlen(d->gettyLine) == 0 ) {
952 if ( (p = index(d->name,':')) != NULL &&
953 ( strncmp(++p,"0",1) == 0 )) {
955 d->gettyLine = (char *) malloc(8);
956 strcpy(d->gettyLine, "console");
959 d->gettyLine = (char *) malloc(3);
960 strcpy(d->gettyLine, "??");
966 * if gettyLine is set to "console", set gettySpeed to "console" also
969 if (d->gettyLine && (strcmp(d->gettyLine, "console") == 0 ) ) {
971 free((char *) d->gettySpeed);
973 d->gettySpeed = (char *) malloc(8);
975 strcpy(d->gettySpeed, "console");
980 * start server. If it cannot be started and this is the console,
984 Debug("Attempting to start server for %s. startTries = %d\n",
985 d->name, d->startTries);
987 if (d->serverPid == -1) {
988 static int bootup = 0;
990 while (bootup++ < 5) {
991 if (GettyRunning(d)) {
1002 if (d->serverPid == -1 &&
1003 (d->startTries++ >= d->startAttempts ||
1006 LogError ((unsigned char *)"Server for display %s can't be started.\n", d->name);
1019 /* this will only happen when using XDMCP */
1020 if (d->authorizations)
1021 SaveServerAuthorizations (d, d->authorizations, d->authNum);
1024 * Generate a utmp ID address for a foreign display. Use the last
1025 * four characters of the DISPLAY name, shifting left if they
1026 * are already in use...
1029 if (d->utmpId == NULL) {
1034 d->utmpId = malloc(sizeof(u->ut_id) +1);
1036 i = strlen (d->name);
1037 if (i >= sizeof (u->ut_id))
1038 i -= sizeof (u->ut_id);
1042 for ( p = d->name, q = d->name + i; p <= q; q-- ) {
1043 (void) strncpy (d->utmpId, q, sizeof (u->ut_id));
1044 d->utmpId[sizeof(u->ut_id)] = '\0';
1045 if (UtmpIdOpen(d->utmpId))
1049 #ifdef DEF_NETWORK_DEV
1051 * If "networkDev" does not start with "/dev/" then foreign
1052 * accounting is turned off. Return utmpId to NULL.
1054 if (networkDev && strncmp(networkDev,"/dev/",5) !=0 ) {
1062 if (NULL == d->authFile)
1063 authFile_str = "NULL";
1065 authFile_str = d->authFile;
1067 Debug("(New StartDisplay) d->authfile %s; authDir %s\n",
1068 authFile_str, authDir);
1071 * make sure stderr is pointing to the current error log file...
1077 if (!nofork_session)
1083 switch (pid = fork ())
1088 if (!nofork_session) {
1090 signal (SIGPIPE, SIG_IGN);
1094 signal (SIGPIPE, SIG_IGN);
1098 * set global display name for Debug()
1106 strncpy(p, d->name, sizeof(DisplayName));
1107 DisplayName[sizeof(DisplayName)-1] = '\0';
1109 if ( (s = strchr(p,':')) != NULL )
1110 if ( (t = strchr(p,'.')) != NULL )
1115 SetAuthorization (d);
1118 * do process accounting...
1122 char *line = (d->displayType.location==Local)
1123 ? d->gettyLine : d->name;
1124 #ifdef DEF_NETWORK_DEV
1125 if (d->displayType.location != Local &&
1126 networkDev && !strncmp(networkDev,"/dev/",5))
1130 struct stat devinfo;
1131 devname = networkDev; /* networkDev resource */
1133 devexists = (lstat(devname,&devinfo)==0);
1135 if (!devexists && (MK_NETWORK_DEV(devname) < 0)) {
1136 Debug("Creation of file '%s' failed:\n %s (%d)\n",
1137 devname,strerror(errno),errno);
1140 for (line=devname; *line; line++);
1141 while (line>devname && *line!='/') line--;
1142 if (*line=='/') line++;
1144 Debug("Using pseudo-tty %s; line=%s\n",
1149 Account(d, "LOGIN", line, getpid(), LOGIN_PROCESS, status);
1152 if (!WaitForServer (d))
1153 exit (OPENFAILED_DISPLAY);
1156 * start the fallback console, if the display is local..
1158 * if the display is remote, fbconsole should be started on
1162 if (d->displayType.location==Local) {
1163 if (d->authFile && strlen(d->authFile) > 0 ) {
1164 strcpy(buff, "XAUTHORITY=");
1165 strcat(buff, d->authFile);
1168 sprintf(start_fbconsole,"%s -d %s &",FBCONSOLE, d->name);
1170 if(system(start_fbconsole) == -1)
1171 Debug("Failed to start the fallback console - %s\n",FBCONSOLE);
1179 exit (REMANAGE_DISPLAY);
1183 Debug ("Child manager process started for %s. pid = %d\n",
1186 d->status = running;
1192 TerminateProcess(int pid, int sig )
1196 kill (pid, SIGCONT);
1201 * transition from running to zombie, suspended, or deleted
1205 StopDisplay( struct display *d )
1209 bzero(&status, sizeof(waitType));
1210 Debug("StopDisplay(): %s, server pid = %d, manager pid = %d, dt_shutdown = %d\n",
1211 d->name, d->serverPid, d->pid, dt_shutdown);
1213 if (d->serverPid != -1)
1214 /* don't remove the console */
1215 if ((d->displayType.location == Local) && !dt_shutdown )
1216 d->status = suspended;
1218 d->status = zombie; /* be careful about race conditions */
1221 TerminateProcess (d->pid, SIGTERM);
1223 if (d->serverPid != -1) {
1224 TerminateProcess (d->serverPid, d->termSignal);
1228 int translate=TR_ASCII;
1230 Debug ("Resetting keyboard\n");
1232 if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) {
1233 Debug("/dev/kbd open failed\n");
1234 } else if (ioctl(kbd_fd, KIOCTRANS, (caddr_t) &translate)) {
1235 Debug("Could not set /dev/kbd back to ASCII mode\n");
1241 if ((d->displayType.location == Local) || !dt_shutdown ) {
1242 /* don't remove the console */
1243 Account(d, NULL, NULL, 0, DEAD_PROCESS, status);
1250 * transition from running to phoenix or notRunning
1254 RestartDisplay( struct display *d, int forceReserver )
1256 if (d->serverPid != -1 && (forceReserver || d->terminateServer))
1258 TerminateProcess (d->serverPid, d->termSignal);
1259 d->status = phoenix;
1263 d->status = notRunning;
1267 static FD_TYPE CloseMask;
1271 RegisterCloseOnFork( int fd )
1273 FD_SET (fd, &CloseMask);
1278 #if 0 /* utility routine: activate if needed... */
1282 FD_CLR (fd, &CloseMask);
1285 if (FD_ISSET (fd, &CloseMask))
1296 for (fd = 0; fd <= max; fd++)
1297 if (FD_ISSET (fd, &CloseMask))
1299 FD_ZERO (&CloseMask);
1304 static FILE *pidFilePtr;
1311 if (pidFile && pidFile[0] != '\0') {
1312 pidFd = open (pidFile, 2);
1313 if (pidFd == -1 && errno == ENOENT)
1316 * HP OSF/1 will not allow an fdopen
1317 * of a file descriptor handed back by creat(2).
1318 * The workaround is to close the created file, and
1319 * open it Read/Write. This will be transparent to HP-UX.
1321 pidFd = creat (pidFile, 0644);
1323 pidFd = open (pidFile, 2);
1325 if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+")))
1327 LogError ((unsigned char *)"Process ID file %s cannot be opened\n",
1331 if (fscanf (pidFilePtr, "%ld", &oldpid) != 1)
1333 fseek (pidFilePtr, 0l, 0);
1336 #if defined (SYSV) || defined (SVR4)
1337 if (lockf (pidFd, F_TLOCK, 0) == -1)
1339 if ((errno == EAGAIN) || (errno == EACCES))
1345 if (flock (pidFd, LOCK_EX|LOCK_NB) == -1)
1347 if (errno == EWOULDBLOCK)
1356 * HPUX releases the lock on ANY close of the file, not just the
1357 * one that established the lock. -prr
1359 /* close(creat(pidFile, 0644)); */
1361 (void) creat(pidFile, 0644);
1362 fprintf (pidFilePtr, "%ld\n", (long)getpid ());
1363 (void) fflush(pidFilePtr);
1364 RegisterCloseOnFork(pidFd);
1370 UnlockPidFile( void )
1373 #if defined (SYSV) || defined (SVR4)
1374 lockf (pidFd, F_ULOCK, 0);
1376 flock (pidFd, LOCK_UN);
1379 fclose (pidFilePtr);
1389 int left = TitleLen;
1396 while (s = va_arg (args, char *))
1398 while (*s && left > 0)
1415 SetTitle( char *name, char *ptr )
1423 * remove domain qualifiers and screens from name...
1426 if ( (p = malloc(strlen(name) + 1)) == NULL) return;
1429 if ( (s = strchr(p,':')) == NULL ) {
1434 if ( (t = strchr(s,'.')) != NULL )
1437 if ( (t = strchr(p,'.')) != NULL )
1441 * if there is enough room shift program name to left,
1442 * then append display name in remaining space.
1448 t = strrchr(s, '/');
1449 if ( (t != NULL) && ((t-s+1) >= (strlen(p) + 3)) ) {
1452 strcpy(s,t); /* "program" */
1453 strcat(s," <"); /* "program <" */
1454 strcat(s,p); /* "program <displayName" */
1455 strcat(s,">"); /* "program <displayName>" */
1458 length = length - strlen(s);
1470 /*****************************************************************************
1473 * Start a "getty" running on the console...
1475 *****************************************************************************/
1477 #if defined (_AIX) && defined (_POWER) || defined (__osf__)
1478 #define GETTYPATH "/usr/sbin/getty"
1479 #elif !defined (__apollo)
1480 #define GETTYPATH "/etc/getty"
1484 StartGetty( struct display *d )
1490 Debug ("StartGetty(): %s\n", d->name);
1492 bzero(&status, sizeof(waitType));
1494 * ensure that server is known dead...
1499 #if !defined(GETTYPATH)
1504 * check to see if we have a valid device (at least a non-null name)...
1507 if ( d->gettyLine &&
1508 (strlen(d->gettyLine) > 0) &&
1509 (strcmp(d->gettyLine,"??") != 0) )
1516 * if there is already a getty running on the device, set up
1517 * to start watching it. When it exits, restart the server...
1520 if ( GettyRunning(d) ) {
1521 d->status = suspended; /* set up to restart server */
1522 wakeupTime = 0; /* enable polling */
1524 sleep(1); /* wait for fbconsole to go away */
1525 GettyMessage(d,1); /* print a help message */
1532 * there is no getty running on the device, try to start one...
1535 d->status = phoenix; /* set up to restart server */
1538 switch (pid = fork ()) {
1543 * do process accounting...
1545 Account(d, "LOGIN", NULL, getpid(), LOGIN_PROCESS, status);
1549 /* The tty argument for getty on AIX must be of the form "/dev/any tty"
1550 and so the following logic
1551 Raghu krovvidi 07.07.93
1553 strcpy(tynm,"/dev/");
1554 strcat(tynm,d->gettyLine);
1556 strcpy(tynm, d->gettyLine);
1559 Debug(" execing getty on %s\n",tynm);
1560 execl(GETTYPATH, "getty", tynm, d->gettySpeed, (char *)0);
1561 LogError ((unsigned char *)"Can not execute %s for %s: errno = %d\n",
1562 GETTYPATH, d->name, errno);
1564 exit (UNMANAGE_DISPLAY);
1567 Debug ("Fork of /etc/getty failed %s\n", d->name);
1568 LogError ((unsigned char *)"Can not fork to execute /etc/getty %s\n", d->name);
1575 Debug ("/etc/getty started on %s\n", d->name);
1578 #endif /* GETTYPATH not defined */
1582 /***************************************************************************
1586 * Print a message on the display device when going into No Windows mode.
1588 ***************************************************************************/
1591 GettyMessage( struct display *d, int msgnum )
1596 strcpy(buf,"/dev/");
1597 strcat(buf,d->gettyLine);
1599 if ( (tf = fopen (buf, "a")) != NULL) {
1601 "\r\n\r\n*****************************************************************************\r\n*\r\n");
1606 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS1_LABEL,MC_DEF_SUS1_LABEL));
1608 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS2_LABEL,MC_DEF_SUS2_LABEL));
1610 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS3_LABEL,MC_DEF_SUS3_LABEL));
1616 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_RES_LABEL,MC_DEF_RES_LABEL));
1623 (char *)ReadCatalog(MC_LABEL_SET,MC_START_LBLDPY,MC_DEF_START_LBLDPY),
1626 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_WAIT_LABEL,MC_DEF_WAIT_LABEL));
1632 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_X_LABEL,MC_DEF_X_LABEL),
1640 "*****************************************************************************\r\n");
1648 /***************************************************************************
1652 * See if a getty process is running against the display device. This
1653 * routine may need to be rewritten on other platforms if a different
1654 * mechanism is needed to make the determination.
1656 * Output: TRUE == a login process is active on the requested device
1657 * FALSE == a login process is not active on the device.
1659 * Sets d->gettyState:
1660 * NONE - no getty running or don't care
1661 * LOGIN - getty running
1662 * USER - user logged in on getty
1664 * Note: The check for a getty process running is made by scanning
1665 * /etc/utmp, looking for a login process on the respective device.
1666 * However, the child Dtlogin spawned by the master Dtlogin to
1667 * handle this display also is a "login process" according to
1668 * /etc/utmp. It provides a login path and therefore must register
1669 * itself as so. If a getty is also running, there are actually two
1670 * login processes running against the same device at the same time.
1672 * The child Dtlogin dies before the scan of /etc/utmp is made.
1673 * Provided /etc/utmp is updated correctly, the Dtlogin entry will
1674 * be marked as dead and will not show up in the scan of /etc/utmp.
1675 ***************************************************************************/
1678 GettyRunning( struct display *d )
1680 struct utmp utmp; /* local struct for new entry */
1681 struct utmp *u; /* pointer to entry in utmp file */
1683 int rvalue; /* return value (TRUE or FALSE) */
1686 d->gettyState = DM_GETTY_NONE;
1689 * check to see if we have a valid device (at least a non-null name)...
1692 if ( d->gettyLine &&
1693 (strlen(d->gettyLine) > 0) &&
1694 (strcmp(d->gettyLine,"??") != 0) )
1700 bzero(&utmp, sizeof(struct utmp));
1703 if (!strcmp(d->gettyLine,"console")) {
1707 fd = open("/dev/console",O_RDONLY);
1708 ttynm = ttyname(fd);
1710 strcpy(utmp.ut_line,ttynm);
1714 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1717 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1720 Debug("Checking for a getty on line %s.\n", utmp.ut_line);
1726 while ( (u = getutent()) != NULL ) {
1728 if ((strncmp(u->ut_line, utmp.ut_line, sizeof(u->ut_line)) != 0) ||
1729 (strncmp(u->ut_id, d->utmpId, sizeof(u->ut_id)) == 0) )
1732 switch (u->ut_type) {
1734 case INIT_PROCESS: strcpy(buf, "INIT_PROCESS"); break;
1735 case LOGIN_PROCESS: strcpy(buf, "LOGIN_PROCESS"); break;
1736 case USER_PROCESS: strcpy(buf, "USER_PROCESS"); break;
1737 case DEAD_PROCESS: strcpy(buf, "DEAD_PROCESS"); break;
1738 default: strcpy(buf, "UNKNOWN"); break;
1741 Debug("Utmp info: id=%.4s, user=%s, line=%s, pid=%d, type=%s\n",
1742 u->ut_id, u->ut_user, u->ut_line, u->ut_pid, buf);
1744 if ( u->ut_type == INIT_PROCESS || u->ut_type == LOGIN_PROCESS) {
1745 d->gettyState = DM_GETTY_LOGIN;
1747 else if (wakeupTime <= 0 && u->ut_type == USER_PROCESS) {
1748 d->gettyState = DM_GETTY_USER;
1751 if (d->gettyState != DM_GETTY_NONE)
1764 /***************************************************************************
1768 * Check if enough time has elapsed since shutdown.
1770 * This is primarily to work with /etc/shutdown. When shutdown kills
1771 * dtlogin (/etc/killall), init immediately restarts it. Shutdown kills
1772 * it again and init restarts it. At each restart, the X-server may start
1773 * on the local display and then subsequently be killed. The user sees a
1774 * flashing screen and sometimes the console is left in an unreset state.
1776 * When Dtlogin shuts down, it touches the access time on the Xservers
1777 * file. (MarkShutdownTime()). This time is then used to determine if
1778 * sufficient time has elapsed before restarting.
1780 ***************************************************************************/
1783 CheckRestartTime( void )
1788 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1790 Debug("Checking restart time.\n");
1793 /* only those other systems are this slow :-) */
1794 sleeptime = 6 - (int) (time((time_t *) 0) - statb.st_atime);
1796 sleeptime = 30 - (int) (time((time_t *) 0) - statb.st_atime);
1799 if ( sleeptime > 30 ) sleeptime = 30;
1801 if ( sleeptime > 0 ) {
1802 Debug("Restarting too soon after shutdown. Sleeping %d seconds.\n",
1811 /***************************************************************************
1815 * Save the time when we shut down to check later for too fast of a restart.
1817 ***************************************************************************/
1820 MarkShutdownTime( void )
1823 struct utimbuf timebuf;
1825 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1827 Debug("Marking shutdown time.\n");
1829 timebuf.actime = time((time_t *) 0 );
1830 timebuf.modtime = statb.st_mtime;
1832 if ( (utime(servers, &timebuf)) != 0 ) {
1833 Debug("MarkShutdownTime(): utime() error = %d\n", errno);
1839 /***************************************************************************
1843 * Make the default dt directory "/var/dt" if needed.
1845 ***************************************************************************/
1847 dtMakeDefaultDir( void )
1849 dtmkdir("/var", 0775);
1850 dtmkdir("/var/dt", 0755);
1851 dtmkdir("/var/dt/tmp", 0755);
1852 dtmkdir("/var/dt/appconfig", 0755);
1853 dtmkdir("/var/dt/appconfig/appmanager", 0755);
1857 dtmkdir(char *dir, mode_t dir_mode)
1859 struct stat file_status;
1861 if ( stat(dir, &file_status) != 0) {
1862 /** try to create it **/
1863 if ( mkdir(dir, dir_mode) == 0) {
1864 chmod(dir, dir_mode); /** since umask is non-zero **/
1865 Debug("Created dir %s\n", dir);
1867 LogError((unsigned char *)"Unable to create dir %s\n", dir);
1870 if ( (file_status.st_mode & dir_mode) != dir_mode) {
1871 /** try to set correct permissions **/
1872 if ( chmod(dir, file_status.st_mode | dir_mode) == 0) {
1873 Debug("Set permissions on %s\n", dir);
1875 LogError((unsigned char *)
1876 "Unable to set permissions on %s\n", dir);