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>
66 #if defined (SYSV) || defined (SVR4)
80 #define sigmask(m) (1 << (( m-1)))
84 /***************************************************************************
86 * External variable declarations
88 ***************************************************************************/
90 #if defined(USL) || defined(__uxp__)
91 extern int makepttypair ();
95 /***************************************************************************
97 * Local procedure declarations
99 ***************************************************************************/
101 static void CheckDisplayStatus( struct display *d) ;
102 static void CheckRestartTime( void ) ;
103 static void ChildNotify( int arg ) ;
104 static void MarkDisplay( struct display *d) ;
105 static void KillDisplay( struct display *d) ;
106 static void MarkShutdownTime( void ) ;
107 static void ProcessChildDeath( int pid, waitType status) ;
108 static void RescanIfMod( void ) ;
109 static void RescanNotify( int arg ) ;
110 static void RescanServers( void ) ;
111 static void RestartDisplay( struct display *d, int forceReserver) ;
112 static int ScanServers( void ) ;
113 static void SetAccessFileTime( void ) ;
114 static void SetConfigFileTime( void ) ;
115 static int StartGetty( struct display *d) ;
116 static void StopAll( int arg ) ;
117 static long StorePid( void ) ;
118 static void TerminateProcess( int pid, int sig) ;
119 static void UnlockPidFile( void ) ;
120 static void dtMakeDefaultDir( void );
121 static void dtmkdir(char *dir, mode_t dir_mode);
126 /***************************************************************************
130 ***************************************************************************/
131 struct passwd puser; /* pseudo-user password entry */
134 static long ServersModTime, ConfigModTime, AccessFileModTime;
138 char DisplayName[32]="main";
141 int nofork_session = 0;
145 char *Title; /* Global argv[0] */
149 static int parent_pid = -1; /* PID of parent dtlogin process */
152 /***************************************************************************/
155 main( int argc, char **argv )
159 struct passwd *p; /* pointer to passwd structure (pwd.h) */
162 * make sure at least world write access is disabled...
164 if ( (oldumask = umask(022) & 002) == 002)
165 (void) umask(oldumask);
169 TitleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - Title;
174 * save program name and path...
177 if ( (progName = malloc(strlen(argv[0]) + 1)) != NULL )
178 strcpy(progName, argv[0]);
180 #if defined(USL) || defined(__uxp__)
181 /* create master slave pair for use in login */
182 if (makepttypair () < 0)
184 Debug ("Could not create pty for use in login");
191 * Step 1 - load configuration parameters
193 InitResources (argc, argv);
194 SetConfigFileTime ();
197 * Only allow root to run xdm to avoid problems (HP 700/X version)
199 if (debugLevel == 0 && getuid() != 0)
202 (char *)ReadCatalog(MC_ERROR_SET,MC_BAD_ROOT,MC_DEF_BAD_ROOT),
207 dtMakeDefaultDir(); /** Create /var/dt if needed **/
208 CheckErrorFile(); /** verify that we can open an error log **/
211 if (debugLevel >= 10)
215 if (debugLevel == 0 && daemonMode)
217 if ( (oldpid = StorePid ()) != 0 )
219 if (oldpid == (long) -1)
221 ReadCatalog(MC_LOG_SET,MC_LOG_NO_CREATE,MC_DEF_LOG_NO_CREATE),
224 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_LOCK,MC_DEF_LOG_NO_LOCK),
230 * Check if we are restarting too fast...
237 * Initialize error file, open XDMCP socket, and set up interrupt handlers.
242 CreateWellKnownSockets ();
243 parent_pid = getpid(); /* PID of parent dtlogin process */
244 (void) signal (SIGTERM, StopAll);
245 (void) signal (SIGINT, StopAll);
248 * Set pseudo-user to "nobody". Xserver will be run as that pseudo-user
249 * rather than root (unless pseudo user is specifically set to another
250 * user via the Xservers file).
253 if ( (p = getpwnam ("nobody")) != NULL) {
257 * This should not happen, the "nobody" user should always be present.
258 * If it does, fall back to traditional values of the "root" user
267 * Ensure the interrupt handlers are set. The Passwd Etc. libraries
268 * (getpwnam()) disable SIGTERM and SIGINT.
271 (void) signal (SIGTERM, StopAll);
272 (void) signal (SIGINT, StopAll);
278 * Step 2 - Read /etc/Xservers and set up
281 * Keep a sub-daemon running
284 SetAccessFileTime ();
285 ScanAccessDatabase ();
286 #if !defined (ENABLE_DYNAMIC_LANGLIST)
288 #endif /* ENABLE_DYNAMIC_LANGLIST */
291 (void) signal (SIGHUP, RescanNotify);
292 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__uxp__)|| defined (__osf__) || defined(linux)
293 (void) signal (SIGCHLD, ChildNotify);
295 while (AnyWellKnownSockets() || AnyDisplaysLeft ())
305 #if defined(SYSV) && !defined(hpux) && !defined(_AIX) && !defined(__uxp__) && !defined (__osf__) && !defined(linux)
313 Debug ("Nothing left to do, exiting\n");
317 RescanNotify( int arg )
319 Debug ("Caught SIGHUP\n");
321 #if defined(SYSV) || defined(SVR4)
322 signal (SIGHUP, RescanNotify);
333 static DisplayType acceptableTypes[] =
334 { { Local, Permanent, FromFile },
335 { Foreign, Permanent, FromFile },
338 #define NumTypes (sizeof (acceptableTypes) / sizeof (acceptableTypes[0]))
340 if (servers[0] == '/')
342 serversFile = fopen (servers, "r");
343 if (serversFile == NULL)
346 ReadCatalog(MC_LOG_SET,MC_LOG_NO_SRVACC,MC_DEF_LOG_NO_SRVACC),
350 if (ServersModTime == 0)
352 fstat (fileno (serversFile), &statb);
353 ServersModTime = statb.st_mtime;
355 while (fgets (lineBuf, sizeof (lineBuf)-1, serversFile))
357 len = strlen (lineBuf);
358 if (lineBuf[len-1] == '\n')
359 lineBuf[len-1] = '\0';
360 ParseDisplay (lineBuf, acceptableTypes, NumTypes, &puser);
362 fclose (serversFile);
366 ParseDisplay (servers, acceptableTypes, NumTypes, &puser);
371 MarkDisplay( struct display *d )
373 d->state = MissingEntry;
377 KillDisplay( struct display *d )
380 Debug("Sending HUP to display %s\n", d->name);
382 Debug("Sending HUP to display ?\n");
384 kill(d->pid, SIGHUP);
388 RescanServers( void )
390 Debug ("Rescanning servers\n");
392 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_REBUILD,MC_DEF_LOG_REBUILD),
394 #if !defined (ENABLE_DYNAMIC_LANGLIST)
396 #endif /* ENABLE_DYNAMIC_LANGLIST */
398 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_RESCAN,MC_DEF_LOG_RESCAN));
399 ForEachDisplay (MarkDisplay);
400 ForEachDisplay (KillDisplay);
404 SetAccessFileTime ();
405 ScanAccessDatabase ();
410 SetConfigFileTime( void )
414 if (stat (config, &statb) != -1)
415 ConfigModTime = statb.st_mtime;
420 SetAccessFileTime( void )
424 if (stat (accessFile, &statb) != -1)
425 AccessFileModTime = statb.st_mtime;
434 if (stat (config, &statb) != -1)
436 if (statb.st_mtime != ConfigModTime)
438 Debug ("Config file %s has changed, rereading\n", config);
440 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADCFG,MC_DEF_LOG_REREADCFG),
442 ConfigModTime = statb.st_mtime;
447 if (servers[0] == '/' && stat(servers, &statb) != -1)
449 if (statb.st_mtime != ServersModTime)
451 Debug ("Servers file %s has changed, rescanning\n", servers);
453 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADSRV,MC_DEF_LOG_REREADSRV),
455 ServersModTime = statb.st_mtime;
456 ForEachDisplay (MarkDisplay);
461 if (accessFile && accessFile[0] && stat (accessFile, &statb) != -1)
463 if (statb.st_mtime != AccessFileModTime)
465 Debug ("Access file %s has changed, rereading\n", accessFile);
467 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADACC,MC_DEF_LOG_REREADACC),
469 AccessFileModTime = statb.st_mtime;
470 ScanAccessDatabase ();
477 * catch a SIGTERM, kill all displays and exit
480 static int dt_shutdown = 0;
485 if (parent_pid != getpid())
488 * we got caught in a race condition - we are really a
489 * child dtlogin process that has been killed by the parent
490 * dtlogin process before we got a chance to return from
491 * fork() and remove this signal handler
493 Debug ("Child dtlogin caught signal %d before it could become a real child\n", arg);
494 (void) signal (arg, SIG_DFL); /* ensure no more handler */
495 TerminateProcess (getpid(), arg); /* and send signal again */
499 Debug ("Shutting down entire manager\n");
500 DestroyWellKnownSockets ();
503 ForEachDisplay (StopDisplay);
504 #if defined(SYSV) || defined(SVR4)
505 /* to avoid another one from killing us unceremoniously */
506 (void) signal (SIGTERM, StopAll);
507 (void) signal (SIGINT, StopAll);
512 * notice that a child has died and may need another
518 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__uxp__) || defined (__osf__) || defined(linux) || defined(CSRG_BASED)
520 ChildNotify( int arg )
528 In HP-UX, SIGCHLDs are queued rather than lost if we are in the middle
529 of processing one (see SIGNAL(5), WARNINGS). The following code relies
532 If we have a socket, then we are using "select" to block
533 (WaitForSomething) rather than "wait". If a child dies, ChildReady is
534 set and the select unblocks. We then loop, processing the child that
535 died plus any that die while we are processing others. Finally we
536 activate the signal handler again and go around one more time in case a
537 child died right before activating the signal handler.
547 #if defined(SYSV) || defined(SVR4) || defined(hpux)
549 if (AnyWellKnownSockets()) {
550 while ( ChildReady ) {
552 while ((pid = waitpid((pid_t) -1, &status, WNOHANG)) > 0 )
554 while ((pid = wait3 (&status, WNOHANG, NULL)) > 0 )
556 ProcessChildDeath(pid, status);
559 (void) signal (SIGCHLD, ChildNotify);
564 /* XXX classic sysV signal race condition here with RescanNotify */
565 if ((pid = wait (&status)) != -1)
566 ProcessChildDeath(pid, status);
570 mask = sigblock (sigmask (SIGCHLD) | sigmask (SIGHUP));
571 Debug ("Signals blocked, mask was 0x%x\n", mask);
572 if (!ChildReady && !Rescan)
577 while ((pid = wait3 (&status, WNOHANG, (struct rusage *) 0)) > 0)
578 ProcessChildDeath(pid, status);
586 ProcessChildDeath( int pid, waitType status )
591 Debug ("Processing child death, pid = %d\n", pid);
595 if ( (d = FindDisplayByPid (pid)) != 0 ) {
599 * do process accounting...
602 #if !defined(CSRG_BASED)
603 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
608 * make sure authorization file is deleted...
612 if (d->authorization && d->authFile) {
613 (void) unlink (d->authFile);
621 * reset "startTries" ...
623 * Local displays: Only for clean exits of the server
624 * Foreign displays: Always except for OPENFAILED_DISPLAY
626 * Note: if startTries expires and a "getty" is run on the local
627 * display, startTries will be reset to zero before
628 * attempting to restart the server.
631 switch (waitVal (status)) {
632 case OBEYSESS_DISPLAY:
633 case RESERVER_DISPLAY:
637 case OPENFAILED_DISPLAY:
641 if (d->displayType.location != Local )
650 * process exit status...
653 switch (waitVal (status)) {
654 case UNMANAGE_DISPLAY:
655 Debug ("Display exited with UNMANAGE_DISPLAY\n");
659 case OBEYSESS_DISPLAY:
660 Debug ("Display exited with (check)OBEYSESS_DISPLAY\n");
661 if (d->displayType.lifetime != Permanent || d->status == zombie)
664 RestartDisplay (d, FALSE);
668 Debug ("Display exited with unknown status %d\n", waitVal(status));
669 LogError ((unsigned char *)"Unknown session exit code %d from process %d\n",
670 waitVal (status), pid);
674 case OPENFAILED_DISPLAY:
675 Debug ("Display exited with OPENFAILED_DISPLAY\n");
676 if (d->displayType.origin == FromXDMCP)
677 SendFailed (d, "Cannot open display");
679 if (d->displayType.location != Local)
682 if (d->displayType.origin == FromXDMCP ||
683 d->status == zombie ||
684 d->startTries >= d->startAttempts)
687 RestartDisplay (d, TRUE);
691 case RESERVER_DISPLAY:
692 Debug ("Display exited with RESERVER_DISPLAY\n");
693 if (d->displayType.origin == FromXDMCP || d->status == zombie)
696 RestartDisplay (d, TRUE);
699 case waitCompose (SIGTERM,0,0):
700 Debug ("Display exited on SIGTERM\n");
701 if (d->displayType.origin == FromXDMCP || d->status == zombie)
704 RestartDisplay (d, TRUE);
707 case REMANAGE_DISPLAY:
708 Debug ("Display exited with REMANAGE_DISPLAY\n");
710 * XDMCP will restart the session if the display
713 if (d->displayType.origin == FromXDMCP || d->status == zombie)
716 RestartDisplay (d, FALSE);
719 case SUSPEND_DISPLAY:
720 Debug ("Display exited with SUSPEND_DISPLAY\n");
721 if (d->displayType.location == Local)
724 RestartDisplay (d, FALSE);
729 else if ( (d = FindDisplayByServerPid (pid)) != 0 )
734 * do process accounting...
737 #if !defined(CSRG_BASED)
738 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
744 Debug ("Zombie server reaped, removing display %s\n", d->name);
748 Debug ("Phoenix server arises, restarting display %s\n", d->name);
749 d->status = notRunning;
752 Debug ("Server for display %s terminated unexpectedly, status %d\n", d->name, waitVal (status));
753 LogError ((unsigned char *)"Server for display %s terminated unexpectedly %d\n",
754 d->name, waitVal(status) );
757 Debug ("Terminating session pid %d\n", d->pid);
758 TerminateProcess (d->pid, SIGTERM);
762 Debug ("Server exited for notRunning session on display %s\n", d->name);
765 Debug ("Server for display %s is suspended\n", d->name);
767 d->status = notRunning;
773 Debug ("Unknown child termination, status %d\n", waitVal (status));
778 CheckDisplayStatus( struct display *d )
781 if (d->displayType.origin == FromFile)
792 Debug("Check %s: status=%d wakeupTime=%d\n", d->name,
793 d->status, wakeupTime);
794 if (d->status == suspended && wakeupTime >= 0)
795 if ( GettyRunning(d) || (strcmp(d->gettyLine,"??") == 0))
796 if ( wakeupTime == 0 ) {
797 Debug("Polling of suspended server %s started.\n",
800 wakeupTime = (wakeupInterval < 10
802 : 2 * wakeupInterval );
805 Debug("Polling of suspended server %s stopped.\n",
807 wakeupTime = -1; /* disable polling */
808 d->status = notRunning; /* restart server */
810 if ( !dt_shutdown ) GettyMessage(d,2);
813 Debug("Polling of suspended server %s continued.\n",
815 wakeupTime = wakeupInterval; /* continue polling*/
818 if (d->status == notRunning)
826 StartDisplays( void )
828 ForEachDisplay (CheckDisplayStatus);
838 char start_fbconsole[1024];
841 Debug ("StartDisplay(): %s\n", d->name);
843 bzero(&status, sizeof(waitType));
844 if (d->authFile == NULL)
845 authFile_str = "NULL";
847 authFile_str = d->authFile;
849 Debug("(Old StartDisplay) d->authfile %s; authDir %s\n",
850 authFile_str, authDir);
853 * The following call to RemoveDisplay is to catch race conditions during
854 * shutdown. There is no point in starting a display if Dtlogin is in the
855 * process of shutting down...
857 if (d->displayType.origin == FromFile && dt_shutdown ) {
863 /* make a backup of the authFile before loading resources and */
864 /* copy it back to authFile field od display structure for X server */
865 /* to reread the host database list on reset */
871 strcpy(bkup ,d->authFile);
873 LoadDisplayResources (d);
875 /* The Xserver may NOT have been killed, so reuse the authFile. */
876 if (NULL == d->authFile &&
878 0 == strncmp(authDir, bkup, strlen(authDir)))
879 d->authFile= (char *) strdup(bkup);
881 if (d->authFile == NULL)
882 authFile_str = "NULL";
884 authFile_str = d->authFile;
886 Debug("(Mid StartDisplay) d->authfile %s; authDir %s; bkup %s\n",
887 authFile_str, authDir, bkup);
890 if (d->displayType.location == Local)
892 /* don't bother pinging local displays; we'll
893 * certainly notice when they exit
898 Debug ("SetLocalAuthorization %s, auth %s\n",
899 d->name, d->authNames);
901 SetLocalAuthorization (d);
904 * reset the server after writing the authorization information
905 * to make it read the file (for compatibility with old
906 * servers which read auth file only on reset instead of
907 * at first connection)
909 if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
910 kill (d->serverPid, d->resetSignal);
915 * initialize d->utmpId. Check to see if anyone else is using
916 * the requested ID. Always allow the first request for "dt" to
917 * succeed as utmp may have become corrupted.
920 if (d->utmpId == NULL) {
921 static int firsttime = 1;
922 static char letters[] = "0123456789abcdefghijklmnopqrstuvwxyzz";
925 d->utmpId = malloc(5);
926 strcpy(d->utmpId, UTMPREC_PREFIX);
932 if ( firsttime || UtmpIdOpen(d->utmpId)) {
937 strncpy(&(d->utmpId[strlen(d->utmpId)]), t++, 1);
939 } while (*t != NULL);
942 Debug ("All DT utmp IDs already in use. Removing display %s\n",
944 LogError ((unsigned char *)"All DT utmp IDs already in use. Removing display %s\n",
953 * set d->gettyLine to "console" for display ":0" if it is not
957 if (! d->gettyLine || strlen(d->gettyLine) == 0 ) {
960 if ( (p = index(d->name,':')) != NULL &&
961 ( strncmp(++p,"0",1) == 0 )) {
963 d->gettyLine = (char *) malloc(8);
964 strcpy(d->gettyLine, "console");
967 d->gettyLine = (char *) malloc(3);
968 strcpy(d->gettyLine, "??");
974 * if gettyLine is set to "console", set gettySpeed to "console" also
977 if (d->gettyLine && (strcmp(d->gettyLine, "console") == 0 ) ) {
979 free((char *) d->gettySpeed);
981 d->gettySpeed = (char *) malloc(8);
983 strcpy(d->gettySpeed, "console");
988 * start server. If it cannot be started and this is the console,
992 Debug("Attempting to start server for %s. startTries = %d\n",
993 d->name, d->startTries);
995 if (d->serverPid == -1) {
996 static int bootup = 0;
998 while (bootup++ < 5) {
999 if (GettyRunning(d)) {
1010 if (d->serverPid == -1 &&
1011 (d->startTries++ >= d->startAttempts ||
1014 LogError ((unsigned char *)"Server for display %s can't be started.\n", d->name);
1027 /* this will only happen when using XDMCP */
1028 if (d->authorizations)
1029 SaveServerAuthorizations (d, d->authorizations, d->authNum);
1032 * Generate a utmp ID address for a foreign display. Use the last
1033 * four characters of the DISPLAY name, shifting left if they
1034 * are already in use...
1037 #if !defined(CSRG_BASED)
1038 if (d->utmpId == NULL) {
1043 d->utmpId = malloc(sizeof(u->ut_id) +1);
1045 i = strlen (d->name);
1046 if (i >= sizeof (u->ut_id))
1047 i -= sizeof (u->ut_id);
1051 for ( p = d->name, q = d->name + i; p <= q; q-- ) {
1052 (void) strncpy (d->utmpId, q, sizeof (u->ut_id));
1053 d->utmpId[sizeof(u->ut_id)] = '\0';
1054 if (UtmpIdOpen(d->utmpId))
1058 #ifdef DEF_NETWORK_DEV
1060 * If "networkDev" does not start with "/dev/" then foreign
1061 * accounting is turned off. Return utmpId to NULL.
1063 if (networkDev && strncmp(networkDev,"/dev/",5) !=0 ) {
1072 if (NULL == d->authFile)
1073 authFile_str = "NULL";
1075 authFile_str = d->authFile;
1077 Debug("(New StartDisplay) d->authfile %s; authDir %s\n",
1078 authFile_str, authDir);
1081 * make sure stderr is pointing to the current error log file...
1087 if (!nofork_session)
1093 switch (pid = fork ())
1098 if (!nofork_session) {
1100 signal (SIGPIPE, SIG_IGN);
1104 signal (SIGPIPE, SIG_IGN);
1108 * set global display name for Debug()
1116 strncpy(p, d->name, sizeof(DisplayName));
1117 DisplayName[sizeof(DisplayName)-1] = '\0';
1119 if ( (s = strchr(p,':')) != NULL )
1120 if ( (t = strchr(p,'.')) != NULL )
1125 SetAuthorization (d);
1128 * do process accounting...
1132 char *line = (d->displayType.location==Local)
1133 ? d->gettyLine : d->name;
1134 #ifdef DEF_NETWORK_DEV
1135 if (d->displayType.location != Local &&
1136 networkDev && !strncmp(networkDev,"/dev/",5))
1140 struct stat devinfo;
1141 devname = networkDev; /* networkDev resource */
1143 devexists = (lstat(devname,&devinfo)==0);
1145 if (!devexists && (MK_NETWORK_DEV(devname) < 0)) {
1146 Debug("Creation of file '%s' failed:\n %s (%d)\n",
1147 devname,strerror(errno),errno);
1150 for (line=devname; *line; line++);
1151 while (line>devname && *line!='/') line--;
1152 if (*line=='/') line++;
1154 Debug("Using pseudo-tty %s; line=%s\n",
1159 #if !defined(CSRG_BASED)
1160 Account(d, "LOGIN", line, getpid(), LOGIN_PROCESS, status);
1164 if (!WaitForServer (d))
1165 exit (OPENFAILED_DISPLAY);
1168 * start the fallback console, if the display is local..
1170 * if the display is remote, fbconsole should be started on
1174 if (d->displayType.location==Local) {
1175 if (d->authFile && strlen(d->authFile) > 0 ) {
1176 strcpy(buff, "XAUTHORITY=");
1177 strcat(buff, d->authFile);
1180 sprintf(start_fbconsole,"%s -d %s &",FBCONSOLE, d->name);
1182 if(system(start_fbconsole) == -1)
1183 Debug("Failed to start the fallback console - %s\n",FBCONSOLE);
1191 exit (REMANAGE_DISPLAY);
1195 Debug ("Child manager process started for %s. pid = %d\n",
1198 d->status = running;
1204 TerminateProcess(int pid, int sig )
1208 kill (pid, SIGCONT);
1213 * transition from running to zombie, suspended, or deleted
1217 StopDisplay( struct display *d )
1221 bzero(&status, sizeof(waitType));
1222 Debug("StopDisplay(): %s, server pid = %d, manager pid = %d, dt_shutdown = %d\n",
1223 d->name, d->serverPid, d->pid, dt_shutdown);
1225 if (d->serverPid != -1)
1226 /* don't remove the console */
1227 if ((d->displayType.location == Local) && !dt_shutdown )
1228 d->status = suspended;
1230 d->status = zombie; /* be careful about race conditions */
1233 TerminateProcess (d->pid, SIGTERM);
1235 if (d->serverPid != -1) {
1236 TerminateProcess (d->serverPid, d->termSignal);
1240 int translate=TR_ASCII;
1242 Debug ("Resetting keyboard\n");
1244 if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) {
1245 Debug("/dev/kbd open failed\n");
1246 } else if (ioctl(kbd_fd, KIOCTRANS, (caddr_t) &translate)) {
1247 Debug("Could not set /dev/kbd back to ASCII mode\n");
1253 if ((d->displayType.location == Local) || !dt_shutdown ) {
1254 /* don't remove the console */
1255 #if !defined(CSRG_BASED)
1256 Account(d, NULL, NULL, 0, DEAD_PROCESS, status);
1264 * transition from running to phoenix or notRunning
1268 RestartDisplay( struct display *d, int forceReserver )
1270 if (d->serverPid != -1 && (forceReserver || d->terminateServer))
1272 TerminateProcess (d->serverPid, d->termSignal);
1273 d->status = phoenix;
1277 d->status = notRunning;
1281 static FD_TYPE CloseMask;
1285 RegisterCloseOnFork( int fd )
1287 FD_SET (fd, &CloseMask);
1292 #if 0 /* utility routine: activate if needed... */
1296 FD_CLR (fd, &CloseMask);
1299 if (FD_ISSET (fd, &CloseMask))
1310 for (fd = 0; fd <= max; fd++)
1311 if (FD_ISSET (fd, &CloseMask))
1313 FD_ZERO (&CloseMask);
1318 static FILE *pidFilePtr;
1325 if (pidFile && pidFile[0] != '\0') {
1326 pidFd = open (pidFile, 2);
1327 if (pidFd == -1 && errno == ENOENT)
1330 * HP OSF/1 will not allow an fdopen
1331 * of a file descriptor handed back by creat(2).
1332 * The workaround is to close the created file, and
1333 * open it Read/Write. This will be transparent to HP-UX.
1335 pidFd = creat (pidFile, 0644);
1337 pidFd = open (pidFile, 2);
1339 if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+")))
1341 LogError ((unsigned char *)"Process ID file %s cannot be opened\n",
1345 if (fscanf (pidFilePtr, "%ld", &oldpid) != 1)
1347 fseek (pidFilePtr, 0l, 0);
1350 #if defined (SYSV) || defined (SVR4)
1351 if (lockf (pidFd, F_TLOCK, 0) == -1)
1353 if ((errno == EAGAIN) || (errno == EACCES))
1359 if (flock (pidFd, LOCK_EX|LOCK_NB) == -1)
1361 if (errno == EWOULDBLOCK)
1370 * HPUX releases the lock on ANY close of the file, not just the
1371 * one that established the lock. -prr
1373 /* close(creat(pidFile, 0644)); */
1375 (void) creat(pidFile, 0644);
1376 fprintf (pidFilePtr, "%ld\n", (long)getpid ());
1377 (void) fflush(pidFilePtr);
1378 RegisterCloseOnFork(pidFd);
1384 UnlockPidFile( void )
1387 #if defined (SYSV) || defined (SVR4)
1388 lockf (pidFd, F_ULOCK, 0);
1390 flock (pidFd, LOCK_UN);
1393 fclose (pidFilePtr);
1403 int left = TitleLen;
1410 while (s = va_arg (args, char *))
1412 while (*s && left > 0)
1429 SetTitle( char *name, char *ptr )
1437 * remove domain qualifiers and screens from name...
1440 if ( (p = malloc(strlen(name) + 1)) == NULL) return;
1443 if ( (s = strchr(p,':')) == NULL ) {
1448 if ( (t = strchr(s,'.')) != NULL )
1451 if ( (t = strchr(p,'.')) != NULL )
1455 * if there is enough room shift program name to left,
1456 * then append display name in remaining space.
1462 t = strrchr(s, '/');
1463 if ( (t != NULL) && ((t-s+1) >= (strlen(p) + 3)) ) {
1466 strcpy(s,t); /* "program" */
1467 strcat(s," <"); /* "program <" */
1468 strcat(s,p); /* "program <displayName" */
1469 strcat(s,">"); /* "program <displayName>" */
1472 length = length - strlen(s);
1484 /*****************************************************************************
1487 * Start a "getty" running on the console...
1489 *****************************************************************************/
1491 #if defined (_AIX) && defined (_POWER) || defined (__osf__)
1492 #define GETTYPATH "/usr/sbin/getty"
1493 #elif !defined (__apollo)
1494 #define GETTYPATH "/etc/getty"
1498 StartGetty( struct display *d )
1504 Debug ("StartGetty(): %s\n", d->name);
1506 bzero(&status, sizeof(waitType));
1508 * ensure that server is known dead...
1513 #if !defined(GETTYPATH)
1518 * check to see if we have a valid device (at least a non-null name)...
1521 if ( d->gettyLine &&
1522 (strlen(d->gettyLine) > 0) &&
1523 (strcmp(d->gettyLine,"??") != 0) )
1530 * if there is already a getty running on the device, set up
1531 * to start watching it. When it exits, restart the server...
1534 if ( GettyRunning(d) ) {
1535 d->status = suspended; /* set up to restart server */
1536 wakeupTime = 0; /* enable polling */
1538 sleep(1); /* wait for fbconsole to go away */
1539 GettyMessage(d,1); /* print a help message */
1546 * there is no getty running on the device, try to start one...
1549 d->status = phoenix; /* set up to restart server */
1552 switch (pid = fork ()) {
1557 * do process accounting...
1559 #if !defined(CSRG_BASED)
1560 Account(d, "LOGIN", NULL, getpid(), LOGIN_PROCESS, status);
1565 /* The tty argument for getty on AIX must be of the form "/dev/any tty"
1566 and so the following logic
1567 Raghu krovvidi 07.07.93
1569 strcpy(tynm,"/dev/");
1570 strcat(tynm,d->gettyLine);
1572 strcpy(tynm, d->gettyLine);
1575 Debug(" execing getty on %s\n",tynm);
1576 execl(GETTYPATH, "getty", tynm, d->gettySpeed, (char *)0);
1577 LogError ((unsigned char *)"Can not execute %s for %s: errno = %d\n",
1578 GETTYPATH, d->name, errno);
1580 exit (UNMANAGE_DISPLAY);
1583 Debug ("Fork of /etc/getty failed %s\n", d->name);
1584 LogError ((unsigned char *)"Can not fork to execute /etc/getty %s\n", d->name);
1591 Debug ("/etc/getty started on %s\n", d->name);
1594 #endif /* GETTYPATH not defined */
1598 /***************************************************************************
1602 * Print a message on the display device when going into No Windows mode.
1604 ***************************************************************************/
1607 GettyMessage( struct display *d, int msgnum )
1612 strcpy(buf,"/dev/");
1613 strcat(buf,d->gettyLine);
1615 if ( (tf = fopen (buf, "a")) != NULL) {
1617 "\r\n\r\n*****************************************************************************\r\n*\r\n");
1622 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS1_LABEL,MC_DEF_SUS1_LABEL));
1624 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS2_LABEL,MC_DEF_SUS2_LABEL));
1626 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS3_LABEL,MC_DEF_SUS3_LABEL));
1632 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_RES_LABEL,MC_DEF_RES_LABEL));
1639 (char *)ReadCatalog(MC_LABEL_SET,MC_START_LBLDPY,MC_DEF_START_LBLDPY),
1642 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_WAIT_LABEL,MC_DEF_WAIT_LABEL));
1648 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_X_LABEL,MC_DEF_X_LABEL),
1656 "*****************************************************************************\r\n");
1664 /***************************************************************************
1668 * See if a getty process is running against the display device. This
1669 * routine may need to be rewritten on other platforms if a different
1670 * mechanism is needed to make the determination.
1672 * Output: TRUE == a login process is active on the requested device
1673 * FALSE == a login process is not active on the device.
1675 * Sets d->gettyState:
1676 * NONE - no getty running or don't care
1677 * LOGIN - getty running
1678 * USER - user logged in on getty
1680 * Note: The check for a getty process running is made by scanning
1681 * /etc/utmp, looking for a login process on the respective device.
1682 * However, the child Dtlogin spawned by the master Dtlogin to
1683 * handle this display also is a "login process" according to
1684 * /etc/utmp. It provides a login path and therefore must register
1685 * itself as so. If a getty is also running, there are actually two
1686 * login processes running against the same device at the same time.
1688 * The child Dtlogin dies before the scan of /etc/utmp is made.
1689 * Provided /etc/utmp is updated correctly, the Dtlogin entry will
1690 * be marked as dead and will not show up in the scan of /etc/utmp.
1691 ***************************************************************************/
1694 GettyRunning( struct display *d )
1696 struct utmp utmp; /* local struct for new entry */
1697 struct utmp *u; /* pointer to entry in utmp file */
1699 int rvalue; /* return value (TRUE or FALSE) */
1702 d->gettyState = DM_GETTY_NONE;
1705 * check to see if we have a valid device (at least a non-null name)...
1708 if ( d->gettyLine &&
1709 (strlen(d->gettyLine) > 0) &&
1710 (strcmp(d->gettyLine,"??") != 0) )
1716 bzero(&utmp, sizeof(struct utmp));
1719 if (!strcmp(d->gettyLine,"console")) {
1723 fd = open("/dev/console",O_RDONLY);
1724 ttynm = ttyname(fd);
1726 strcpy(utmp.ut_line,ttynm);
1730 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1733 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1736 Debug("Checking for a getty on line %s.\n", utmp.ut_line);
1738 #if !defined(CSRG_BASED)
1743 while ( (u = getutent()) != NULL ) {
1745 if ((strncmp(u->ut_line, utmp.ut_line, sizeof(u->ut_line)) != 0) ||
1746 (strncmp(u->ut_id, d->utmpId, sizeof(u->ut_id)) == 0) )
1749 switch (u->ut_type) {
1751 case INIT_PROCESS: strcpy(buf, "INIT_PROCESS"); break;
1752 case LOGIN_PROCESS: strcpy(buf, "LOGIN_PROCESS"); break;
1753 case USER_PROCESS: strcpy(buf, "USER_PROCESS"); break;
1754 case DEAD_PROCESS: strcpy(buf, "DEAD_PROCESS"); break;
1755 default: strcpy(buf, "UNKNOWN"); break;
1758 Debug("Utmp info: id=%.4s, user=%s, line=%s, pid=%d, type=%s\n",
1759 u->ut_id, u->ut_user, u->ut_line, u->ut_pid, buf);
1761 if ( u->ut_type == INIT_PROCESS || u->ut_type == LOGIN_PROCESS) {
1762 d->gettyState = DM_GETTY_LOGIN;
1764 else if (wakeupTime <= 0 && u->ut_type == USER_PROCESS) {
1765 d->gettyState = DM_GETTY_USER;
1768 if (d->gettyState != DM_GETTY_NONE)
1776 #endif /* !CSRG_BASED */
1782 /***************************************************************************
1786 * Check if enough time has elapsed since shutdown.
1788 * This is primarily to work with /etc/shutdown. When shutdown kills
1789 * dtlogin (/etc/killall), init immediately restarts it. Shutdown kills
1790 * it again and init restarts it. At each restart, the X-server may start
1791 * on the local display and then subsequently be killed. The user sees a
1792 * flashing screen and sometimes the console is left in an unreset state.
1794 * When Dtlogin shuts down, it touches the access time on the Xservers
1795 * file. (MarkShutdownTime()). This time is then used to determine if
1796 * sufficient time has elapsed before restarting.
1798 ***************************************************************************/
1801 CheckRestartTime( void )
1806 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1808 Debug("Checking restart time.\n");
1811 /* only those other systems are this slow :-) */
1812 sleeptime = 6 - (int) (time((time_t *) 0) - statb.st_atime);
1814 sleeptime = 30 - (int) (time((time_t *) 0) - statb.st_atime);
1817 if ( sleeptime > 30 ) sleeptime = 30;
1819 if ( sleeptime > 0 ) {
1820 Debug("Restarting too soon after shutdown. Sleeping %d seconds.\n",
1829 /***************************************************************************
1833 * Save the time when we shut down to check later for too fast of a restart.
1835 ***************************************************************************/
1838 MarkShutdownTime( void )
1841 struct utimbuf timebuf;
1843 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1845 Debug("Marking shutdown time.\n");
1847 timebuf.actime = time((time_t *) 0 );
1848 timebuf.modtime = statb.st_mtime;
1850 if ( (utime(servers, &timebuf)) != 0 ) {
1851 Debug("MarkShutdownTime(): utime() error = %d\n", errno);
1857 /***************************************************************************
1861 * Make the default dt directory "/var/dt" if needed.
1863 ***************************************************************************/
1865 dtMakeDefaultDir( void )
1867 dtmkdir("/var", 0775);
1868 dtmkdir("/var/dt", 0755);
1869 dtmkdir("/var/dt/tmp", 0755);
1870 dtmkdir("/var/dt/appconfig", 0755);
1871 dtmkdir("/var/dt/appconfig/appmanager", 0755);
1875 dtmkdir(char *dir, mode_t dir_mode)
1877 struct stat file_status;
1879 if ( stat(dir, &file_status) != 0) {
1880 /** try to create it **/
1881 if ( mkdir(dir, dir_mode) == 0) {
1882 chmod(dir, dir_mode); /** since umask is non-zero **/
1883 Debug("Created dir %s\n", dir);
1885 LogError((unsigned char *)"Unable to create dir %s\n", dir);
1888 if ( (file_status.st_mode & dir_mode) != dir_mode) {
1889 /** try to set correct permissions **/
1890 if ( chmod(dir, file_status.st_mode | dir_mode) == 0) {
1891 Debug("Set permissions on %s\n", dir);
1893 LogError((unsigned char *)
1894 "Unable to set permissions on %s\n", dir);