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>
56 #if defined(__FreeBSD__) && OSMAJORVERSION > 8
64 #if defined(linux) || defined(__FreeBSD__)
70 #if defined (SYSV) || defined (SVR4)
84 #define sigmask(m) (1 << (( m-1)))
88 /***************************************************************************
90 * External variable declarations
92 ***************************************************************************/
94 #if defined(USL) || defined(__uxp__)
95 extern int makepttypair ();
99 /***************************************************************************
101 * Local procedure declarations
103 ***************************************************************************/
105 static void CheckDisplayStatus( struct display *d) ;
106 static void CheckRestartTime( void ) ;
107 static void ChildNotify( int arg ) ;
108 static void MarkDisplay( struct display *d) ;
109 static void KillDisplay( struct display *d) ;
110 static void MarkShutdownTime( void ) ;
111 static void ProcessChildDeath( int pid, waitType status) ;
112 static void RescanIfMod( void ) ;
113 static void RescanNotify( int arg ) ;
114 static void RescanServers( void ) ;
115 static void RestartDisplay( struct display *d, int forceReserver) ;
116 static int ScanServers( void ) ;
117 static void SetAccessFileTime( void ) ;
118 static void SetConfigFileTime( void ) ;
119 static int StartGetty( struct display *d) ;
120 static void StopAll( int arg ) ;
121 static long StorePid( void ) ;
122 static void TerminateProcess( int pid, int sig) ;
123 static void UnlockPidFile( void ) ;
124 static void dtMakeDefaultDir( void );
125 static void dtmkdir(char *dir, mode_t dir_mode, int force);
130 /***************************************************************************
134 ***************************************************************************/
135 struct passwd puser; /* pseudo-user password entry */
138 static long ServersModTime, ConfigModTime, AccessFileModTime;
142 char DisplayName[32]="main";
145 int nofork_session = 0;
149 char *Title; /* Global argv[0] */
153 static int parent_pid = -1; /* PID of parent dtlogin process */
156 /***************************************************************************/
159 main( int argc, char **argv )
163 struct passwd *p; /* pointer to passwd structure (pwd.h) */
166 * make sure at least world write access is disabled...
168 if ( (oldumask = umask(022) & 002) == 002)
169 (void) umask(oldumask);
173 TitleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - Title;
178 * save program name and path...
181 if ( (progName = malloc(strlen(argv[0]) + 1)) != NULL )
182 strcpy(progName, argv[0]);
184 #if defined(USL) || defined(__uxp__)
185 /* create master slave pair for use in login */
186 if (makepttypair () < 0)
188 Debug ("Could not create pty for use in login");
195 * Step 1 - load configuration parameters
197 InitResources (argc, argv);
198 SetConfigFileTime ();
201 * Only allow root to run xdm to avoid problems (HP 700/X version)
203 if (debugLevel == 0 && getuid() != 0)
206 (char *)ReadCatalog(MC_ERROR_SET,MC_BAD_ROOT,MC_DEF_BAD_ROOT),
211 dtMakeDefaultDir(); /** Create /var/dt if needed **/
212 CheckErrorFile(); /** verify that we can open an error log **/
215 if (debugLevel >= 10)
219 if (debugLevel == 0 && daemonMode)
221 if ( (oldpid = StorePid ()) != 0 )
223 if (oldpid == (long) -1)
225 ReadCatalog(MC_LOG_SET,MC_LOG_NO_CREATE,MC_DEF_LOG_NO_CREATE),
228 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_LOCK,MC_DEF_LOG_NO_LOCK),
234 * Check if we are restarting too fast...
241 * Initialize error file, open XDMCP socket, and set up interrupt handlers.
246 CreateWellKnownSockets ();
247 parent_pid = getpid(); /* PID of parent dtlogin process */
248 (void) signal (SIGTERM, StopAll);
249 (void) signal (SIGINT, StopAll);
252 * Set pseudo-user to "nobody". Xserver will be run as that pseudo-user
253 * rather than root (unless pseudo user is specifically set to another
254 * user via the Xservers file).
257 if ( (p = getpwnam ("nobody")) != NULL) {
261 * This should not happen, the "nobody" user should always be present.
262 * If it does, fall back to traditional values of the "root" user
271 * Ensure the interrupt handlers are set. The Passwd Etc. libraries
272 * (getpwnam()) disable SIGTERM and SIGINT.
275 (void) signal (SIGTERM, StopAll);
276 (void) signal (SIGINT, StopAll);
282 * Step 2 - Read /etc/Xservers and set up
285 * Keep a sub-daemon running
288 SetAccessFileTime ();
289 ScanAccessDatabase ();
290 #if !defined (ENABLE_DYNAMIC_LANGLIST)
292 #endif /* ENABLE_DYNAMIC_LANGLIST */
295 (void) signal (SIGHUP, RescanNotify);
296 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__uxp__)|| defined (__osf__) || defined(linux)
297 (void) signal (SIGCHLD, ChildNotify);
299 while (AnyWellKnownSockets() || AnyDisplaysLeft ())
309 #if defined(SYSV) && !defined(hpux) && !defined(_AIX) && !defined(__uxp__) && !defined (__osf__) && !defined(linux)
317 Debug ("Nothing left to do, exiting\n");
321 RescanNotify( int arg )
323 Debug ("Caught SIGHUP\n");
325 #if defined(SYSV) || defined(SVR4)
326 signal (SIGHUP, RescanNotify);
337 static DisplayType acceptableTypes[] =
338 { { Local, Permanent, FromFile },
339 { Foreign, Permanent, FromFile },
342 #define NumTypes (sizeof (acceptableTypes) / sizeof (acceptableTypes[0]))
344 if (servers[0] == '/')
346 serversFile = fopen (servers, "r");
347 if (serversFile == NULL)
350 ReadCatalog(MC_LOG_SET,MC_LOG_NO_SRVACC,MC_DEF_LOG_NO_SRVACC),
354 if (ServersModTime == 0)
356 fstat (fileno (serversFile), &statb);
357 ServersModTime = statb.st_mtime;
359 while (fgets (lineBuf, sizeof (lineBuf)-1, serversFile))
361 len = strlen (lineBuf);
362 if (lineBuf[len-1] == '\n')
363 lineBuf[len-1] = '\0';
364 ParseDisplay (lineBuf, acceptableTypes, NumTypes, &puser);
366 fclose (serversFile);
370 ParseDisplay (servers, acceptableTypes, NumTypes, &puser);
375 MarkDisplay( struct display *d )
377 d->state = MissingEntry;
381 KillDisplay( struct display *d )
384 Debug("Sending HUP to display %s\n", d->name);
386 Debug("Sending HUP to display ?\n");
388 kill(d->pid, SIGHUP);
392 RescanServers( void )
394 Debug ("Rescanning servers\n");
396 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_REBUILD,MC_DEF_LOG_REBUILD),
398 #if !defined (ENABLE_DYNAMIC_LANGLIST)
400 #endif /* ENABLE_DYNAMIC_LANGLIST */
402 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_RESCAN,MC_DEF_LOG_RESCAN));
403 ForEachDisplay (MarkDisplay);
404 ForEachDisplay (KillDisplay);
408 SetAccessFileTime ();
409 ScanAccessDatabase ();
414 SetConfigFileTime( void )
418 if (stat (config, &statb) != -1)
419 ConfigModTime = statb.st_mtime;
424 SetAccessFileTime( void )
428 if (stat (accessFile, &statb) != -1)
429 AccessFileModTime = statb.st_mtime;
438 if (stat (config, &statb) != -1)
440 if (statb.st_mtime != ConfigModTime)
442 Debug ("Config file %s has changed, rereading\n", config);
444 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADCFG,MC_DEF_LOG_REREADCFG),
446 ConfigModTime = statb.st_mtime;
451 if (servers[0] == '/' && stat(servers, &statb) != -1)
453 if (statb.st_mtime != ServersModTime)
455 Debug ("Servers file %s has changed, rescanning\n", servers);
457 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADSRV,MC_DEF_LOG_REREADSRV),
459 ServersModTime = statb.st_mtime;
460 ForEachDisplay (MarkDisplay);
465 if (accessFile && accessFile[0] && stat (accessFile, &statb) != -1)
467 if (statb.st_mtime != AccessFileModTime)
469 Debug ("Access file %s has changed, rereading\n", accessFile);
471 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADACC,MC_DEF_LOG_REREADACC),
473 AccessFileModTime = statb.st_mtime;
474 ScanAccessDatabase ();
481 * catch a SIGTERM, kill all displays and exit
484 static int dt_shutdown = 0;
489 if (parent_pid != getpid())
492 * we got caught in a race condition - we are really a
493 * child dtlogin process that has been killed by the parent
494 * dtlogin process before we got a chance to return from
495 * fork() and remove this signal handler
497 Debug ("Child dtlogin caught signal %d before it could become a real child\n", arg);
498 (void) signal (arg, SIG_DFL); /* ensure no more handler */
499 TerminateProcess (getpid(), arg); /* and send signal again */
503 Debug ("Shutting down entire manager\n");
504 DestroyWellKnownSockets ();
507 ForEachDisplay (StopDisplay);
508 #if defined(SYSV) || defined(SVR4)
509 /* to avoid another one from killing us unceremoniously */
510 (void) signal (SIGTERM, StopAll);
511 (void) signal (SIGINT, StopAll);
516 * notice that a child has died and may need another
522 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__uxp__) || defined (__osf__) || defined(linux) || defined(CSRG_BASED)
524 ChildNotify( int arg )
532 In HP-UX, SIGCHLDs are queued rather than lost if we are in the middle
533 of processing one (see SIGNAL(5), WARNINGS). The following code relies
536 If we have a socket, then we are using "select" to block
537 (WaitForSomething) rather than "wait". If a child dies, ChildReady is
538 set and the select unblocks. We then loop, processing the child that
539 died plus any that die while we are processing others. Finally we
540 activate the signal handler again and go around one more time in case a
541 child died right before activating the signal handler.
551 #if defined(SYSV) || defined(SVR4) || defined(hpux)
553 if (AnyWellKnownSockets()) {
554 while ( ChildReady ) {
556 while ((pid = waitpid((pid_t) -1, &status, WNOHANG)) > 0 )
558 while ((pid = wait3 (&status, WNOHANG, NULL)) > 0 )
560 ProcessChildDeath(pid, status);
563 (void) signal (SIGCHLD, ChildNotify);
568 /* XXX classic sysV signal race condition here with RescanNotify */
569 if ((pid = wait (&status)) != -1)
570 ProcessChildDeath(pid, status);
574 mask = sigblock (sigmask (SIGCHLD) | sigmask (SIGHUP));
575 Debug ("Signals blocked, mask was 0x%x\n", mask);
576 if (!ChildReady && !Rescan)
581 while ((pid = wait3 (&status, WNOHANG, (struct rusage *) 0)) > 0)
582 ProcessChildDeath(pid, status);
590 ProcessChildDeath( int pid, waitType status )
595 Debug ("Processing child death, pid = %d\n", pid);
599 if ( (d = FindDisplayByPid (pid)) != 0 ) {
603 * do process accounting...
606 #if !defined(CSRG_BASED)
607 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
612 * make sure authorization file is deleted...
616 if (d->authorization && d->authFile) {
617 (void) unlink (d->authFile);
625 * reset "startTries" ...
627 * Local displays: Only for clean exits of the server
628 * Foreign displays: Always except for OPENFAILED_DISPLAY
630 * Note: if startTries expires and a "getty" is run on the local
631 * display, startTries will be reset to zero before
632 * attempting to restart the server.
635 switch (waitVal (status)) {
636 case OBEYSESS_DISPLAY:
637 case RESERVER_DISPLAY:
641 case OPENFAILED_DISPLAY:
645 if (d->displayType.location != Local )
654 * process exit status...
657 switch (waitVal (status)) {
658 case UNMANAGE_DISPLAY:
659 Debug ("Display exited with UNMANAGE_DISPLAY\n");
663 case OBEYSESS_DISPLAY:
664 Debug ("Display exited with (check)OBEYSESS_DISPLAY\n");
665 if (d->displayType.lifetime != Permanent || d->status == zombie)
668 RestartDisplay (d, FALSE);
672 Debug ("Display exited with unknown status %d\n", waitVal(status));
673 LogError ((unsigned char *)"Unknown session exit code %d from process %d\n",
674 waitVal (status), pid);
678 case OPENFAILED_DISPLAY:
679 Debug ("Display exited with OPENFAILED_DISPLAY\n");
680 if (d->displayType.origin == FromXDMCP)
681 SendFailed (d, "Cannot open display");
683 if (d->displayType.location != Local)
686 if (d->displayType.origin == FromXDMCP ||
687 d->status == zombie ||
688 d->startTries >= d->startAttempts)
691 RestartDisplay (d, TRUE);
695 case RESERVER_DISPLAY:
696 Debug ("Display exited with RESERVER_DISPLAY\n");
697 if (d->displayType.origin == FromXDMCP || d->status == zombie)
700 RestartDisplay (d, TRUE);
703 case waitCompose (SIGTERM,0,0):
704 Debug ("Display exited on SIGTERM\n");
705 if (d->displayType.origin == FromXDMCP || d->status == zombie)
708 RestartDisplay (d, TRUE);
711 case REMANAGE_DISPLAY:
712 Debug ("Display exited with REMANAGE_DISPLAY\n");
714 * XDMCP will restart the session if the display
717 if (d->displayType.origin == FromXDMCP || d->status == zombie)
720 RestartDisplay (d, FALSE);
723 case SUSPEND_DISPLAY:
724 Debug ("Display exited with SUSPEND_DISPLAY\n");
725 if (d->displayType.location == Local)
728 RestartDisplay (d, FALSE);
733 else if ( (d = FindDisplayByServerPid (pid)) != 0 )
738 * do process accounting...
741 #if !defined(CSRG_BASED)
742 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
748 Debug ("Zombie server reaped, removing display %s\n", d->name);
752 Debug ("Phoenix server arises, restarting display %s\n", d->name);
753 d->status = notRunning;
756 Debug ("Server for display %s terminated unexpectedly, status %d\n", d->name, waitVal (status));
757 LogError ((unsigned char *)"Server for display %s terminated unexpectedly %d\n",
758 d->name, waitVal(status) );
761 Debug ("Terminating session pid %d\n", d->pid);
762 TerminateProcess (d->pid, SIGTERM);
766 Debug ("Server exited for notRunning session on display %s\n", d->name);
769 Debug ("Server for display %s is suspended\n", d->name);
771 d->status = notRunning;
777 Debug ("Unknown child termination, status %d\n", waitVal (status));
782 CheckDisplayStatus( struct display *d )
785 if (d->displayType.origin == FromFile)
796 Debug("Check %s: status=%d wakeupTime=%d\n", d->name,
797 d->status, wakeupTime);
798 if (d->status == suspended && wakeupTime >= 0)
799 if ( GettyRunning(d) || (strcmp(d->gettyLine,"??") == 0))
800 if ( wakeupTime == 0 ) {
801 Debug("Polling of suspended server %s started.\n",
804 wakeupTime = (wakeupInterval < 10
806 : 2 * wakeupInterval );
809 Debug("Polling of suspended server %s stopped.\n",
811 wakeupTime = -1; /* disable polling */
812 d->status = notRunning; /* restart server */
814 if ( !dt_shutdown ) GettyMessage(d,2);
817 Debug("Polling of suspended server %s continued.\n",
819 wakeupTime = wakeupInterval; /* continue polling*/
822 if (d->status == notRunning)
830 StartDisplays( void )
832 ForEachDisplay (CheckDisplayStatus);
842 char start_fbconsole[1024];
845 Debug ("StartDisplay(): %s\n", d->name);
847 bzero(&status, sizeof(waitType));
848 if (d->authFile == NULL)
849 authFile_str = "NULL";
851 authFile_str = d->authFile;
853 Debug("(Old StartDisplay) d->authfile %s; authDir %s\n",
854 authFile_str, authDir);
857 * The following call to RemoveDisplay is to catch race conditions during
858 * shutdown. There is no point in starting a display if Dtlogin is in the
859 * process of shutting down...
861 if (d->displayType.origin == FromFile && dt_shutdown ) {
867 /* make a backup of the authFile before loading resources and */
868 /* copy it back to authFile field od display structure for X server */
869 /* to reread the host database list on reset */
875 strcpy(bkup ,d->authFile);
877 LoadDisplayResources (d);
879 /* The Xserver may NOT have been killed, so reuse the authFile. */
880 if (NULL == d->authFile &&
882 0 == strncmp(authDir, bkup, strlen(authDir)))
883 d->authFile= (char *) strdup(bkup);
885 if (d->authFile == NULL)
886 authFile_str = "NULL";
888 authFile_str = d->authFile;
890 Debug("(Mid StartDisplay) d->authfile %s; authDir %s; bkup %s\n",
891 authFile_str, authDir, bkup);
894 if (d->displayType.location == Local)
896 /* don't bother pinging local displays; we'll
897 * certainly notice when they exit
902 Debug ("SetLocalAuthorization %s, auth %s\n",
903 d->name, d->authNames);
905 SetLocalAuthorization (d);
908 * reset the server after writing the authorization information
909 * to make it read the file (for compatibility with old
910 * servers which read auth file only on reset instead of
911 * at first connection)
913 if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
914 kill (d->serverPid, d->resetSignal);
919 * initialize d->utmpId. Check to see if anyone else is using
920 * the requested ID. Always allow the first request for "dt" to
921 * succeed as utmp may have become corrupted.
924 if (d->utmpId == NULL) {
925 static int firsttime = 1;
926 static char letters[] = "0123456789abcdefghijklmnopqrstuvwxyzz";
929 d->utmpId = malloc(5);
930 strcpy(d->utmpId, UTMPREC_PREFIX);
936 if ( firsttime || UtmpIdOpen(d->utmpId)) {
941 strncpy(&(d->utmpId[strlen(d->utmpId)]), t++, 1);
943 } while (*t != '\0');
946 Debug ("All DT utmp IDs already in use. Removing display %s\n",
948 LogError ((unsigned char *)"All DT utmp IDs already in use. Removing display %s\n",
957 * set d->gettyLine to "console" for display ":0" if it is not
961 if (! d->gettyLine || strlen(d->gettyLine) == 0 ) {
964 if ( (p = index(d->name,':')) != NULL &&
965 ( strncmp(++p,"0",1) == 0 )) {
967 d->gettyLine = (char *) malloc(8);
968 strcpy(d->gettyLine, "console");
971 d->gettyLine = (char *) malloc(3);
972 strcpy(d->gettyLine, "??");
978 * if gettyLine is set to "console", set gettySpeed to "console" also
981 if (d->gettyLine && (strcmp(d->gettyLine, "console") == 0 ) ) {
983 free((char *) d->gettySpeed);
985 d->gettySpeed = (char *) malloc(8);
987 strcpy(d->gettySpeed, "console");
992 * start server. If it cannot be started and this is the console,
996 Debug("Attempting to start server for %s. startTries = %d\n",
997 d->name, d->startTries);
999 if (d->serverPid == -1) {
1000 static int bootup = 0;
1002 while (bootup++ < 5) {
1003 if (GettyRunning(d)) {
1014 if (d->serverPid == -1 &&
1015 (d->startTries++ >= d->startAttempts ||
1018 LogError ((unsigned char *)"Server for display %s can't be started.\n", d->name);
1031 /* this will only happen when using XDMCP */
1032 if (d->authorizations)
1033 SaveServerAuthorizations (d, d->authorizations, d->authNum);
1036 * Generate a utmp ID address for a foreign display. Use the last
1037 * four characters of the DISPLAY name, shifting left if they
1038 * are already in use...
1041 #if !defined(CSRG_BASED)
1042 if (d->utmpId == NULL) {
1047 d->utmpId = malloc(sizeof(u->ut_id) +1);
1049 i = strlen (d->name);
1050 if (i >= sizeof (u->ut_id))
1051 i -= sizeof (u->ut_id);
1055 for ( p = d->name, q = d->name + i; p <= q; q-- ) {
1056 (void) strncpy (d->utmpId, q, sizeof (u->ut_id));
1057 d->utmpId[sizeof(u->ut_id)] = '\0';
1058 if (UtmpIdOpen(d->utmpId))
1062 #ifdef DEF_NETWORK_DEV
1064 * If "networkDev" does not start with "/dev/" then foreign
1065 * accounting is turned off. Return utmpId to NULL.
1067 if (networkDev && strncmp(networkDev,"/dev/",5) !=0 ) {
1076 if (NULL == d->authFile)
1077 authFile_str = "NULL";
1079 authFile_str = d->authFile;
1081 Debug("(New StartDisplay) d->authfile %s; authDir %s\n",
1082 authFile_str, authDir);
1085 * make sure stderr is pointing to the current error log file...
1091 if (!nofork_session)
1097 switch (pid = fork ())
1102 if (!nofork_session) {
1104 signal (SIGPIPE, SIG_IGN);
1108 signal (SIGPIPE, SIG_IGN);
1112 * set global display name for Debug()
1120 strncpy(p, d->name, sizeof(DisplayName));
1121 DisplayName[sizeof(DisplayName)-1] = '\0';
1123 if ( (s = strchr(p,':')) != NULL )
1124 if ( (t = strchr(p,'.')) != NULL )
1129 SetAuthorization (d);
1132 * do process accounting...
1136 char *line = (d->displayType.location==Local)
1137 ? d->gettyLine : d->name;
1138 #ifdef DEF_NETWORK_DEV
1139 if (d->displayType.location != Local &&
1140 networkDev && !strncmp(networkDev,"/dev/",5))
1144 struct stat devinfo;
1145 devname = networkDev; /* networkDev resource */
1147 devexists = (lstat(devname,&devinfo)==0);
1149 if (!devexists && (MK_NETWORK_DEV(devname) < 0)) {
1150 Debug("Creation of file '%s' failed:\n %s (%d)\n",
1151 devname,strerror(errno),errno);
1154 for (line=devname; *line; line++);
1155 while (line>devname && *line!='/') line--;
1156 if (*line=='/') line++;
1158 Debug("Using pseudo-tty %s; line=%s\n",
1163 #if !defined(CSRG_BASED)
1164 Account(d, "LOGIN", line, getpid(), LOGIN_PROCESS, status);
1168 if (!WaitForServer (d))
1169 exit (OPENFAILED_DISPLAY);
1172 * start the fallback console, if the display is local..
1174 * if the display is remote, fbconsole should be started on
1178 if (d->displayType.location==Local) {
1179 if (d->authFile && strlen(d->authFile) > 0 ) {
1180 strcpy(buff, "XAUTHORITY=");
1181 strcat(buff, d->authFile);
1184 sprintf(start_fbconsole,"%s -d %s &",FBCONSOLE, d->name);
1186 if(system(start_fbconsole) == -1)
1187 Debug("Failed to start the fallback console - %s\n",FBCONSOLE);
1195 exit (REMANAGE_DISPLAY);
1199 Debug ("Child manager process started for %s. pid = %d\n",
1202 d->status = running;
1208 TerminateProcess(int pid, int sig )
1212 kill (pid, SIGCONT);
1217 * transition from running to zombie, suspended, or deleted
1221 StopDisplay( struct display *d )
1225 bzero(&status, sizeof(waitType));
1226 Debug("StopDisplay(): %s, server pid = %d, manager pid = %d, dt_shutdown = %d\n",
1227 d->name, d->serverPid, d->pid, dt_shutdown);
1229 if (d->serverPid != -1)
1230 /* don't remove the console */
1231 if ((d->displayType.location == Local) && !dt_shutdown )
1232 d->status = suspended;
1234 d->status = zombie; /* be careful about race conditions */
1237 TerminateProcess (d->pid, SIGTERM);
1239 if (d->serverPid != -1) {
1240 TerminateProcess (d->serverPid, d->termSignal);
1244 int translate=TR_ASCII;
1246 Debug ("Resetting keyboard\n");
1248 if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) {
1249 Debug("/dev/kbd open failed\n");
1250 } else if (ioctl(kbd_fd, KIOCTRANS, (caddr_t) &translate)) {
1251 Debug("Could not set /dev/kbd back to ASCII mode\n");
1257 if ((d->displayType.location == Local) || !dt_shutdown ) {
1258 /* don't remove the console */
1259 #if !defined(CSRG_BASED)
1260 Account(d, NULL, NULL, 0, DEAD_PROCESS, status);
1268 * transition from running to phoenix or notRunning
1272 RestartDisplay( struct display *d, int forceReserver )
1274 if (d->serverPid != -1 && (forceReserver || d->terminateServer))
1276 TerminateProcess (d->serverPid, d->termSignal);
1277 d->status = phoenix;
1281 d->status = notRunning;
1285 static FD_TYPE CloseMask;
1289 RegisterCloseOnFork( int fd )
1291 FD_SET (fd, &CloseMask);
1296 #if 0 /* utility routine: activate if needed... */
1300 FD_CLR (fd, &CloseMask);
1303 if (FD_ISSET (fd, &CloseMask))
1314 for (fd = 0; fd <= max; fd++)
1315 if (FD_ISSET (fd, &CloseMask))
1317 FD_ZERO (&CloseMask);
1322 static FILE *pidFilePtr;
1329 if (pidFile && pidFile[0] != '\0') {
1330 pidFd = open (pidFile, 2);
1331 if (pidFd == -1 && errno == ENOENT)
1334 * HP OSF/1 will not allow an fdopen
1335 * of a file descriptor handed back by creat(2).
1336 * The workaround is to close the created file, and
1337 * open it Read/Write. This will be transparent to HP-UX.
1339 pidFd = creat (pidFile, 0644);
1341 pidFd = open (pidFile, 2);
1343 if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+")))
1345 LogError ((unsigned char *)"Process ID file %s cannot be opened\n",
1349 if (fscanf (pidFilePtr, "%ld", &oldpid) != 1)
1351 fseek (pidFilePtr, 0l, 0);
1354 #if defined (SYSV) || defined (SVR4)
1355 if (lockf (pidFd, F_TLOCK, 0) == -1)
1357 if ((errno == EAGAIN) || (errno == EACCES))
1363 if (flock (pidFd, LOCK_EX|LOCK_NB) == -1)
1365 if (errno == EWOULDBLOCK)
1374 * HPUX releases the lock on ANY close of the file, not just the
1375 * one that established the lock. -prr
1377 /* close(creat(pidFile, 0644)); */
1379 (void) creat(pidFile, 0644);
1380 fprintf (pidFilePtr, "%ld\n", (long)getpid ());
1381 (void) fflush(pidFilePtr);
1382 RegisterCloseOnFork(pidFd);
1388 UnlockPidFile( void )
1391 #if defined (SYSV) || defined (SVR4)
1392 lockf (pidFd, F_ULOCK, 0);
1394 flock (pidFd, LOCK_UN);
1397 fclose (pidFilePtr);
1407 int left = TitleLen;
1414 while (s = va_arg (args, char *))
1416 while (*s && left > 0)
1433 SetTitle( char *name, char *ptr )
1441 * remove domain qualifiers and screens from name...
1444 if ( (p = malloc(strlen(name) + 1)) == NULL) return;
1447 if ( (s = strchr(p,':')) == NULL ) {
1452 if ( (t = strchr(s,'.')) != NULL )
1455 if ( (t = strchr(p,'.')) != NULL )
1459 * if there is enough room shift program name to left,
1460 * then append display name in remaining space.
1466 t = strrchr(s, '/');
1467 if ( (t != NULL) && ((t-s+1) >= (strlen(p) + 3)) ) {
1470 strcpy(s,t); /* "program" */
1471 strcat(s," <"); /* "program <" */
1472 strcat(s,p); /* "program <displayName" */
1473 strcat(s,">"); /* "program <displayName>" */
1476 length = length - strlen(s);
1488 /*****************************************************************************
1491 * Start a "getty" running on the console...
1493 *****************************************************************************/
1495 #if defined (_AIX) && defined (_POWER) || defined (__osf__)
1496 #define GETTYPATH "/usr/sbin/getty"
1497 #elif !defined (__apollo)
1498 #define GETTYPATH "/etc/getty"
1502 StartGetty( struct display *d )
1508 Debug ("StartGetty(): %s\n", d->name);
1510 bzero(&status, sizeof(waitType));
1512 * ensure that server is known dead...
1517 #if !defined(GETTYPATH)
1522 * check to see if we have a valid device (at least a non-null name)...
1525 if ( d->gettyLine &&
1526 (strlen(d->gettyLine) > 0) &&
1527 (strcmp(d->gettyLine,"??") != 0) )
1534 * if there is already a getty running on the device, set up
1535 * to start watching it. When it exits, restart the server...
1538 if ( GettyRunning(d) ) {
1539 d->status = suspended; /* set up to restart server */
1540 wakeupTime = 0; /* enable polling */
1542 sleep(1); /* wait for fbconsole to go away */
1543 GettyMessage(d,1); /* print a help message */
1550 * there is no getty running on the device, try to start one...
1553 d->status = phoenix; /* set up to restart server */
1556 switch (pid = fork ()) {
1561 * do process accounting...
1563 #if !defined(CSRG_BASED)
1564 Account(d, "LOGIN", NULL, getpid(), LOGIN_PROCESS, status);
1569 /* The tty argument for getty on AIX must be of the form "/dev/any tty"
1570 and so the following logic
1571 Raghu krovvidi 07.07.93
1573 strcpy(tynm,"/dev/");
1574 strcat(tynm,d->gettyLine);
1576 strcpy(tynm, d->gettyLine);
1579 Debug(" execing getty on %s\n",tynm);
1580 execl(GETTYPATH, "getty", tynm, d->gettySpeed, (char *)0);
1581 LogError ((unsigned char *)"Can not execute %s for %s: errno = %d\n",
1582 GETTYPATH, d->name, errno);
1584 exit (UNMANAGE_DISPLAY);
1587 Debug ("Fork of /etc/getty failed %s\n", d->name);
1588 LogError ((unsigned char *)"Can not fork to execute /etc/getty %s\n", d->name);
1595 Debug ("/etc/getty started on %s\n", d->name);
1598 #endif /* GETTYPATH not defined */
1602 /***************************************************************************
1606 * Print a message on the display device when going into No Windows mode.
1608 ***************************************************************************/
1611 GettyMessage( struct display *d, int msgnum )
1616 strcpy(buf,"/dev/");
1617 strcat(buf,d->gettyLine);
1619 if ( (tf = fopen (buf, "a")) != NULL) {
1621 "\r\n\r\n*****************************************************************************\r\n*\r\n");
1626 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_SUS1_LABEL,MC_DEF_SUS1_LABEL));
1628 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_SUS2_LABEL,MC_DEF_SUS2_LABEL));
1630 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_SUS3_LABEL,MC_DEF_SUS3_LABEL));
1636 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_RES_LABEL,MC_DEF_RES_LABEL));
1643 (char *)ReadCatalog(MC_LABEL_SET,MC_START_LBLDPY,MC_DEF_START_LBLDPY),
1646 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_WAIT_LABEL,MC_DEF_WAIT_LABEL));
1652 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_X_LABEL,MC_DEF_X_LABEL),
1660 "*****************************************************************************\r\n");
1668 /***************************************************************************
1672 * See if a getty process is running against the display device. This
1673 * routine may need to be rewritten on other platforms if a different
1674 * mechanism is needed to make the determination.
1676 * Output: TRUE == a login process is active on the requested device
1677 * FALSE == a login process is not active on the device.
1679 * Sets d->gettyState:
1680 * NONE - no getty running or don't care
1681 * LOGIN - getty running
1682 * USER - user logged in on getty
1684 * Note: The check for a getty process running is made by scanning
1685 * /etc/utmp, looking for a login process on the respective device.
1686 * However, the child Dtlogin spawned by the master Dtlogin to
1687 * handle this display also is a "login process" according to
1688 * /etc/utmp. It provides a login path and therefore must register
1689 * itself as so. If a getty is also running, there are actually two
1690 * login processes running against the same device at the same time.
1692 * The child Dtlogin dies before the scan of /etc/utmp is made.
1693 * Provided /etc/utmp is updated correctly, the Dtlogin entry will
1694 * be marked as dead and will not show up in the scan of /etc/utmp.
1695 ***************************************************************************/
1698 GettyRunning( struct display *d )
1700 #if defined(__FreeBSD__) && OSMAJORVERSION > 8
1701 struct utmpx utmp; /* local struct for new entry */
1702 struct utmpx *u; /* pointer to entry in utmp file */
1704 struct utmp utmp; /* local struct for new entry */
1705 struct utmp *u; /* pointer to entry in utmp file */
1708 int rvalue; /* return value (TRUE or FALSE) */
1711 d->gettyState = DM_GETTY_NONE;
1714 * check to see if we have a valid device (at least a non-null name)...
1717 if ( d->gettyLine &&
1718 (strlen(d->gettyLine) > 0) &&
1719 (strcmp(d->gettyLine,"??") != 0) )
1725 #if defined(__FreeBSD__) && OSMAJORVERSION > 8
1726 bzero(&utmp, sizeof(struct utmpx));
1728 bzero(&utmp, sizeof(struct utmp));
1732 if (!strcmp(d->gettyLine,"console")) {
1736 fd = open("/dev/console",O_RDONLY);
1737 ttynm = ttyname(fd);
1739 strcpy(utmp.ut_line,ttynm);
1743 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1746 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1749 Debug("Checking for a getty on line %s.\n", utmp.ut_line);
1751 #if !defined(CSRG_BASED)
1756 while ( (u = getutent()) != NULL ) {
1758 if ((strncmp(u->ut_line, utmp.ut_line, sizeof(u->ut_line)) != 0) ||
1759 (strncmp(u->ut_id, d->utmpId, sizeof(u->ut_id)) == 0) )
1762 switch (u->ut_type) {
1764 case INIT_PROCESS: strcpy(buf, "INIT_PROCESS"); break;
1765 case LOGIN_PROCESS: strcpy(buf, "LOGIN_PROCESS"); break;
1766 case USER_PROCESS: strcpy(buf, "USER_PROCESS"); break;
1767 case DEAD_PROCESS: strcpy(buf, "DEAD_PROCESS"); break;
1768 default: strcpy(buf, "UNKNOWN"); break;
1771 Debug("Utmp info: id=%.4s, user=%s, line=%s, pid=%d, type=%s\n",
1772 u->ut_id, u->ut_user, u->ut_line, u->ut_pid, buf);
1774 if ( u->ut_type == INIT_PROCESS || u->ut_type == LOGIN_PROCESS) {
1775 d->gettyState = DM_GETTY_LOGIN;
1777 else if (wakeupTime <= 0 && u->ut_type == USER_PROCESS) {
1778 d->gettyState = DM_GETTY_USER;
1781 if (d->gettyState != DM_GETTY_NONE)
1789 #endif /* !CSRG_BASED */
1795 /***************************************************************************
1799 * Check if enough time has elapsed since shutdown.
1801 * This is primarily to work with /etc/shutdown. When shutdown kills
1802 * dtlogin (/etc/killall), init immediately restarts it. Shutdown kills
1803 * it again and init restarts it. At each restart, the X-server may start
1804 * on the local display and then subsequently be killed. The user sees a
1805 * flashing screen and sometimes the console is left in an unreset state.
1807 * When Dtlogin shuts down, it touches the access time on the Xservers
1808 * file. (MarkShutdownTime()). This time is then used to determine if
1809 * sufficient time has elapsed before restarting.
1811 ***************************************************************************/
1814 CheckRestartTime( void )
1819 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1821 Debug("Checking restart time.\n");
1824 /* only those other systems are this slow :-) */
1825 sleeptime = 6 - (int) (time((time_t *) 0) - statb.st_atime);
1827 sleeptime = 30 - (int) (time((time_t *) 0) - statb.st_atime);
1830 if ( sleeptime > 30 ) sleeptime = 30;
1832 if ( sleeptime > 0 ) {
1833 Debug("Restarting too soon after shutdown. Sleeping %d seconds.\n",
1842 /***************************************************************************
1846 * Save the time when we shut down to check later for too fast of a restart.
1848 ***************************************************************************/
1851 MarkShutdownTime( void )
1854 struct utimbuf timebuf;
1856 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1858 Debug("Marking shutdown time.\n");
1860 timebuf.actime = time((time_t *) 0 );
1861 timebuf.modtime = statb.st_mtime;
1863 if ( (utime(servers, &timebuf)) != 0 ) {
1864 Debug("MarkShutdownTime(): utime() error = %d\n", errno);
1870 /***************************************************************************
1874 * Make the default dt directory "/var/dt" if needed.
1876 ***************************************************************************/
1878 dtMakeDefaultDir( void )
1880 dtmkdir("/var", 0755, 0);
1881 dtmkdir("/var/dt", 0755, 1);
1882 dtmkdir("/var/dt/tmp", 0755, 1);
1883 dtmkdir("/var/dt/appconfig", 0755, 1);
1884 dtmkdir("/var/dt/appconfig/appmanager", 0755, 1);
1888 dtmkdir(char *dir, mode_t dir_mode, int force)
1890 struct stat file_status;
1892 if ( stat(dir, &file_status) != 0) {
1893 /** try to create it **/
1894 if ( mkdir(dir, dir_mode) == 0) {
1895 chmod(dir, dir_mode); /** since umask is non-zero **/
1896 Debug("Created dir %s\n", dir);
1898 LogError((unsigned char *)"Unable to create dir %s\n", dir);
1901 if ( force && (file_status.st_mode & dir_mode) != dir_mode) {
1902 /** try to set correct permissions **/
1903 if ( chmod(dir, file_status.st_mode | dir_mode) == 0) {
1904 Debug("Set permissions on %s\n", dir);
1906 LogError((unsigned char *)
1907 "Unable to set permissions on %s\n", dir);