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 libraries 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/types.h>
55 # include <sys/signal.h>
56 # include <sys/stat.h>
57 #if defined(__FreeBSD__) && OSMAJORVERSION > 8
65 #if defined(linux) || defined(CSRG_BASED) || defined(sun)
71 #if defined (SYSV) || defined (SVR4)
85 #define sigmask(m) (1 << (( m-1)))
89 /***************************************************************************
91 * External variable declarations
93 ***************************************************************************/
96 extern int makepttypair ();
100 /***************************************************************************
102 * Local procedure declarations
104 ***************************************************************************/
106 static void CheckDisplayStatus( struct display *d) ;
107 static void CheckRestartTime( void ) ;
108 static void ChildNotify( int arg ) ;
109 static void MarkDisplay( struct display *d) ;
110 static void KillDisplay( struct display *d) ;
111 static void MarkShutdownTime( void ) ;
112 static void ProcessChildDeath( int pid, waitType status) ;
113 static void RescanIfMod( void ) ;
114 static void RescanNotify( int arg ) ;
115 static void RescanServers( void ) ;
116 static void RestartDisplay( struct display *d, int forceReserver) ;
117 static int ScanServers( void ) ;
118 static void SetAccessFileTime( void ) ;
119 static void SetConfigFileTime( void ) ;
120 static int StartGetty( struct display *d) ;
121 static void StopAll( int arg ) ;
122 static long StorePid( void ) ;
123 static void TerminateProcess( int pid, int sig) ;
124 static void UnlockPidFile( void ) ;
125 static void dtMakeDefaultDir( void );
126 static void dtmkdir(char *dir, mode_t dir_mode, int force);
131 /***************************************************************************
135 ***************************************************************************/
136 struct passwd puser; /* pseudo-user password entry */
139 static long ServersModTime, ConfigModTime, AccessFileModTime;
143 char DisplayName[32]="main";
146 int nofork_session = 0;
150 char *Title; /* Global argv[0] */
154 static int parent_pid = -1; /* PID of parent dtlogin process */
157 /***************************************************************************/
160 main( int argc, char **argv )
164 struct passwd *p; /* pointer to passwd structure (pwd.h) */
167 * make sure at least world write access is disabled...
169 if ( (oldumask = umask(022) & 002) == 002)
170 (void) umask(oldumask);
174 TitleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - Title;
179 * save program name and path...
182 if ( (progName = malloc(strlen(argv[0]) + 1)) != NULL )
183 strcpy(progName, argv[0]);
186 /* create master slave pair for use in login */
187 if (makepttypair () < 0)
189 Debug ("Could not create pty for use in login");
196 * Step 1 - load configuration parameters
198 InitResources (argc, argv);
199 SetConfigFileTime ();
202 * Only allow root to run xdm to avoid problems (HP 700/X version)
204 if (debugLevel == 0 && getuid() != 0)
207 (char *)ReadCatalog(MC_ERROR_SET,MC_BAD_ROOT,MC_DEF_BAD_ROOT),
212 dtMakeDefaultDir(); /** Create /var/dt if needed **/
213 CheckErrorFile(); /** verify that we can open an error log **/
216 if (debugLevel >= 10)
220 if (debugLevel == 0 && daemonMode)
222 if ( (oldpid = StorePid ()) != 0 )
224 if (oldpid == (long) -1)
226 ReadCatalog(MC_LOG_SET,MC_LOG_NO_CREATE,MC_DEF_LOG_NO_CREATE),
229 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_LOCK,MC_DEF_LOG_NO_LOCK),
235 * Check if we are restarting too fast...
242 * Initialize error file, open XDMCP socket, and set up interrupt handlers.
247 CreateWellKnownSockets ();
248 parent_pid = getpid(); /* PID of parent dtlogin process */
249 (void) signal (SIGTERM, StopAll);
250 (void) signal (SIGINT, StopAll);
253 * Set pseudo-user to "nobody". Xserver will be run as that pseudo-user
254 * rather than root (unless pseudo user is specifically set to another
255 * user via the Xservers file).
258 if ( (p = getpwnam ("nobody")) != NULL) {
262 * This should not happen, the "nobody" user should always be present.
263 * If it does, fall back to traditional values of the "root" user
272 * Ensure the interrupt handlers are set. The Passwd Etc. libraries
273 * (getpwnam()) disable SIGTERM and SIGINT.
276 (void) signal (SIGTERM, StopAll);
277 (void) signal (SIGINT, StopAll);
283 * Step 2 - Read /etc/Xservers and set up
286 * Keep a sub-daemon running
289 SetAccessFileTime ();
290 ScanAccessDatabase ();
291 #if !defined (ENABLE_DYNAMIC_LANGLIST)
293 #endif /* ENABLE_DYNAMIC_LANGLIST */
296 (void) signal (SIGHUP, RescanNotify);
297 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined (__osf__) || defined(linux)
298 (void) signal (SIGCHLD, ChildNotify);
300 while (AnyWellKnownSockets() || AnyDisplaysLeft ())
310 #if defined(SYSV) && !defined(hpux) && !defined(_AIX) && !defined (__osf__) && !defined(linux)
318 Debug ("Nothing left to do, exiting\n");
322 RescanNotify( int arg )
324 Debug ("Caught SIGHUP\n");
326 #if defined(SYSV) || defined(SVR4)
327 signal (SIGHUP, RescanNotify);
338 static DisplayType acceptableTypes[] =
339 { { Local, Permanent, FromFile },
340 { Foreign, Permanent, FromFile },
343 #define NumTypes (sizeof (acceptableTypes) / sizeof (acceptableTypes[0]))
345 if (servers[0] == '/')
347 serversFile = fopen (servers, "r");
348 if (serversFile == NULL)
351 ReadCatalog(MC_LOG_SET,MC_LOG_NO_SRVACC,MC_DEF_LOG_NO_SRVACC),
355 if (ServersModTime == 0)
357 fstat (fileno (serversFile), &statb);
358 ServersModTime = statb.st_mtime;
360 while (fgets (lineBuf, sizeof (lineBuf)-1, serversFile))
362 len = strlen (lineBuf);
363 if (lineBuf[len-1] == '\n')
364 lineBuf[len-1] = '\0';
365 ParseDisplay (lineBuf, acceptableTypes, NumTypes, &puser);
367 fclose (serversFile);
371 ParseDisplay (servers, acceptableTypes, NumTypes, &puser);
377 MarkDisplay( struct display *d )
379 d->state = MissingEntry;
383 KillDisplay( struct display *d )
386 Debug("Sending HUP to display %s\n", d->name);
388 Debug("Sending HUP to display ?\n");
390 kill(d->pid, SIGHUP);
394 RescanServers( void )
396 Debug ("Rescanning servers\n");
398 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_REBUILD,MC_DEF_LOG_REBUILD),
400 #if !defined (ENABLE_DYNAMIC_LANGLIST)
402 #endif /* ENABLE_DYNAMIC_LANGLIST */
404 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_RESCAN,MC_DEF_LOG_RESCAN));
405 ForEachDisplay (MarkDisplay);
406 ForEachDisplay (KillDisplay);
410 SetAccessFileTime ();
411 ScanAccessDatabase ();
416 SetConfigFileTime( void )
420 if (stat (config, &statb) != -1)
421 ConfigModTime = statb.st_mtime;
426 SetAccessFileTime( void )
430 if (stat (accessFile, &statb) != -1)
431 AccessFileModTime = statb.st_mtime;
440 if (stat (config, &statb) != -1)
442 if (statb.st_mtime != ConfigModTime)
444 Debug ("Config file %s has changed, rereading\n", config);
446 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADCFG,MC_DEF_LOG_REREADCFG),
448 ConfigModTime = statb.st_mtime;
453 if (servers[0] == '/' && stat(servers, &statb) != -1)
455 if (statb.st_mtime != ServersModTime)
457 Debug ("Servers file %s has changed, rescanning\n", servers);
459 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADSRV,MC_DEF_LOG_REREADSRV),
461 ServersModTime = statb.st_mtime;
462 ForEachDisplay (MarkDisplay);
467 if (accessFile && accessFile[0] && stat (accessFile, &statb) != -1)
469 if (statb.st_mtime != AccessFileModTime)
471 Debug ("Access file %s has changed, rereading\n", accessFile);
473 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADACC,MC_DEF_LOG_REREADACC),
475 AccessFileModTime = statb.st_mtime;
476 ScanAccessDatabase ();
483 * catch a SIGTERM, kill all displays and exit
486 static int dt_shutdown = 0;
491 if (parent_pid != getpid())
494 * we got caught in a race condition - we are really a
495 * child dtlogin process that has been killed by the parent
496 * dtlogin process before we got a chance to return from
497 * fork() and remove this signal handler
499 Debug ("Child dtlogin caught signal %d before it could become a real child\n", arg);
500 (void) signal (arg, SIG_DFL); /* ensure no more handler */
501 TerminateProcess (getpid(), arg); /* and send signal again */
505 Debug ("Shutting down entire manager\n");
506 DestroyWellKnownSockets ();
509 ForEachDisplay (StopDisplay);
510 #if defined(SYSV) || defined(SVR4)
511 /* to avoid another one from killing us unceremoniously */
512 (void) signal (SIGTERM, StopAll);
513 (void) signal (SIGINT, StopAll);
518 * notice that a child has died and may need another
524 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined (__osf__) || defined(linux) || defined(CSRG_BASED)
526 ChildNotify( int arg )
534 In HP-UX, SIGCHLDs are queued rather than lost if we are in the middle
535 of processing one (see SIGNAL(5), WARNINGS). The following code relies
538 If we have a socket, then we are using "select" to block
539 (WaitForSomething) rather than "wait". If a child dies, ChildReady is
540 set and the select unblocks. We then loop, processing the child that
541 died plus any that die while we are processing others. Finally we
542 activate the signal handler again and go around one more time in case a
543 child died right before activating the signal handler.
553 #if defined(SYSV) || defined(SVR4) || defined(hpux)
555 if (AnyWellKnownSockets()) {
556 while ( ChildReady ) {
558 while ((pid = waitpid((pid_t) -1, &status, WNOHANG)) > 0 )
560 while ((pid = wait3 (&status, WNOHANG, NULL)) > 0 )
562 ProcessChildDeath(pid, status);
565 (void) signal (SIGCHLD, ChildNotify);
570 /* XXX classic sysV signal race condition here with RescanNotify */
571 if ((pid = wait (&status)) != -1)
572 ProcessChildDeath(pid, status);
576 mask = sigblock (sigmask (SIGCHLD) | sigmask (SIGHUP));
577 Debug ("Signals blocked, mask was 0x%x\n", mask);
578 if (!ChildReady && !Rescan)
583 while ((pid = wait3 (&status, WNOHANG, (struct rusage *) 0)) > 0)
584 ProcessChildDeath(pid, status);
592 ProcessChildDeath( int pid, waitType status )
597 Debug ("Processing child death, pid = %d\n", pid);
601 if ( (d = FindDisplayByPid (pid)) != 0 ) {
605 * do process accounting...
608 #if !defined(CSRG_BASED)
609 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
614 * make sure authorization file is deleted...
618 if (d->authorization && d->authFile) {
619 (void) unlink (d->authFile);
627 * reset "startTries" ...
629 * Local displays: Only for clean exits of the server
630 * Foreign displays: Always except for OPENFAILED_DISPLAY
632 * Note: if startTries expires and a "getty" is run on the local
633 * display, startTries will be reset to zero before
634 * attempting to restart the server.
637 switch (waitVal (status)) {
638 case OBEYSESS_DISPLAY:
639 case RESERVER_DISPLAY:
643 case OPENFAILED_DISPLAY:
647 if (d->displayType.location != Local )
656 * process exit status...
659 switch (waitVal (status)) {
660 case UNMANAGE_DISPLAY:
661 Debug ("Display exited with UNMANAGE_DISPLAY\n");
665 case OBEYSESS_DISPLAY:
666 Debug ("Display exited with (check)OBEYSESS_DISPLAY\n");
667 if (d->displayType.lifetime != Permanent || d->status == zombie)
670 RestartDisplay (d, FALSE);
674 Debug ("Display exited with unknown status %d\n", waitVal(status));
675 LogError ((unsigned char *)"Unknown session exit code %d from process %d\n",
676 waitVal (status), pid);
680 case OPENFAILED_DISPLAY:
681 Debug ("Display exited with OPENFAILED_DISPLAY\n");
682 if (d->displayType.origin == FromXDMCP)
683 SendFailed (d, "Cannot open display");
685 if (d->displayType.location != Local)
688 if (d->displayType.origin == FromXDMCP ||
689 d->status == zombie ||
690 d->startTries >= d->startAttempts)
693 RestartDisplay (d, TRUE);
697 case RESERVER_DISPLAY:
698 Debug ("Display exited with RESERVER_DISPLAY\n");
699 if (d->displayType.origin == FromXDMCP || d->status == zombie)
702 RestartDisplay (d, TRUE);
705 case waitCompose (SIGTERM,0,0):
706 Debug ("Display exited on SIGTERM\n");
707 if (d->displayType.origin == FromXDMCP || d->status == zombie)
710 RestartDisplay (d, TRUE);
713 case REMANAGE_DISPLAY:
714 Debug ("Display exited with REMANAGE_DISPLAY\n");
716 * XDMCP will restart the session if the display
719 if (d->displayType.origin == FromXDMCP || d->status == zombie)
722 RestartDisplay (d, FALSE);
725 case SUSPEND_DISPLAY:
726 Debug ("Display exited with SUSPEND_DISPLAY\n");
727 if (d->displayType.location == Local)
730 RestartDisplay (d, FALSE);
735 else if ( (d = FindDisplayByServerPid (pid)) != 0 )
740 * do process accounting...
743 #if !defined(CSRG_BASED)
744 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
750 Debug ("Zombie server reaped, removing display %s\n", d->name);
754 Debug ("Phoenix server arises, restarting display %s\n", d->name);
755 d->status = notRunning;
758 Debug ("Server for display %s terminated unexpectedly, status %d\n", d->name, waitVal (status));
759 LogError ((unsigned char *)"Server for display %s terminated unexpectedly %d\n",
760 d->name, waitVal(status) );
763 Debug ("Terminating session pid %d\n", d->pid);
764 TerminateProcess (d->pid, SIGTERM);
768 Debug ("Server exited for notRunning session on display %s\n", d->name);
771 Debug ("Server for display %s is suspended\n", d->name);
773 d->status = notRunning;
779 Debug ("Unknown child termination, status %d\n", waitVal (status));
784 CheckDisplayStatus( struct display *d )
787 if (d->displayType.origin == FromFile)
798 Debug("Check %s: status=%d wakeupTime=%d\n", d->name,
799 d->status, wakeupTime);
800 if (d->status == suspended && wakeupTime >= 0)
801 if ( GettyRunning(d) || (d->gettyLine && (strcmp(d->gettyLine,"??") == 0)) )
802 if ( wakeupTime == 0 ) {
803 Debug("Polling of suspended server %s started.\n",
806 wakeupTime = (wakeupInterval < 10
808 : 2 * wakeupInterval );
811 Debug("Polling of suspended server %s stopped.\n",
813 wakeupTime = -1; /* disable polling */
814 d->status = notRunning; /* restart server */
816 if ( !dt_shutdown ) GettyMessage(d,2);
819 Debug("Polling of suspended server %s continued.\n",
821 wakeupTime = wakeupInterval; /* continue polling*/
824 if (d->status == notRunning)
832 StartDisplays( void )
834 ForEachDisplay (CheckDisplayStatus);
844 char start_fbconsole[1024];
847 Debug ("StartDisplay(): %s\n", d->name);
849 bzero(&status, sizeof(waitType));
850 if (d->authFile == NULL)
851 authFile_str = "NULL";
853 authFile_str = d->authFile;
855 Debug("(Old StartDisplay) d->authfile %s; authDir %s\n",
856 authFile_str, authDir);
859 * The following call to RemoveDisplay is to catch race conditions during
860 * shutdown. There is no point in starting a display if Dtlogin is in the
861 * process of shutting down...
863 if (d->displayType.origin == FromFile && dt_shutdown ) {
869 /* make a backup of the authFile before loading resources and */
870 /* copy it back to authFile field od display structure for X server */
871 /* to reread the host database list on reset */
877 snprintf(bkup, sizeof(bkup), "%s", d->authFile);
879 LoadDisplayResources (d);
881 /* The Xserver may NOT have been killed, so reuse the authFile. */
882 if (NULL == d->authFile &&
884 0 == strncmp(authDir, bkup, strlen(authDir)))
885 d->authFile= (char *) strdup(bkup);
887 if (d->authFile == NULL)
888 authFile_str = "NULL";
890 authFile_str = d->authFile;
892 Debug("(Mid StartDisplay) d->authfile %s; authDir %s; bkup %s\n",
893 authFile_str, authDir, bkup);
896 if (d->displayType.location == Local)
898 /* don't bother pinging local displays; we'll
899 * certainly notice when they exit
904 Debug ("SetLocalAuthorization %s, auth %s\n",
905 d->name, d->authNames);
907 SetLocalAuthorization (d);
910 * reset the server after writing the authorization information
911 * to make it read the file (for compatibility with old
912 * servers which read auth file only on reset instead of
913 * at first connection)
915 if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
916 kill (d->serverPid, d->resetSignal);
921 * initialize d->utmpId. Check to see if anyone else is using
922 * the requested ID. Always allow the first request for "dt" to
923 * succeed as utmp may have become corrupted.
926 if (d->utmpId == NULL) {
927 static int firsttime = 1;
928 static char letters[] = "0123456789abcdefghijklmnopqrstuvwxyzz";
931 d->utmpId = malloc(5);
932 strcpy(d->utmpId, UTMPREC_PREFIX);
938 if ( firsttime || UtmpIdOpen(d->utmpId)) {
943 strncpy(&(d->utmpId[strlen(d->utmpId)]), t++, 1);
945 } while (*t != '\0');
948 Debug ("All DT utmp IDs already in use. Removing display %s\n",
950 LogError ((unsigned char *)"All DT utmp IDs already in use. Removing display %s\n",
959 * set d->gettyLine to "console" for display ":0" if it is not
963 if (! d->gettyLine || strlen(d->gettyLine) == 0 ) {
966 if ( (p = index(d->name,':')) != NULL &&
967 ( strncmp(++p,"0",1) == 0 )) {
969 d->gettyLine = (char *) malloc(8);
970 strcpy(d->gettyLine, "console");
973 d->gettyLine = (char *) malloc(3);
974 strcpy(d->gettyLine, "??");
980 * if gettyLine is set to "console", set gettySpeed to "console" also
983 if (d->gettyLine && (strcmp(d->gettyLine, "console") == 0 ) ) {
985 free((char *) d->gettySpeed);
987 d->gettySpeed = (char *) malloc(8);
989 strcpy(d->gettySpeed, "console");
994 * start server. If it cannot be started and this is the console,
998 Debug("Attempting to start server for %s. startTries = %d\n",
999 d->name, d->startTries);
1001 if (d->serverPid == -1) {
1002 static int bootup = 0;
1004 while (bootup++ < 5) {
1005 if (GettyRunning(d)) {
1016 if (d->serverPid == -1 &&
1017 (d->startTries++ >= d->startAttempts ||
1020 LogError ((unsigned char *)"Server for display %s can't be started.\n", d->name);
1033 /* this will only happen when using XDMCP */
1034 if (d->authorizations)
1035 SaveServerAuthorizations (d, d->authorizations, d->authNum);
1038 * Generate a utmp ID address for a foreign display. Use the last
1039 * four characters of the DISPLAY name, shifting left if they
1040 * are already in use...
1043 #if !defined(CSRG_BASED)
1044 if (d->utmpId == NULL) {
1049 d->utmpId = malloc(sizeof(u->ut_id) +1);
1051 i = strlen (d->name);
1052 if (i >= sizeof (u->ut_id))
1053 i -= sizeof (u->ut_id);
1057 for ( p = d->name, q = d->name + i; p <= q; q-- ) {
1058 (void) strncpy (d->utmpId, q, sizeof (u->ut_id));
1059 d->utmpId[sizeof(u->ut_id)] = '\0';
1060 if (UtmpIdOpen(d->utmpId))
1064 #ifdef DEF_NETWORK_DEV
1066 * If "networkDev" does not start with "/dev/" then foreign
1067 * accounting is turned off. Return utmpId to NULL.
1069 if (networkDev && strncmp(networkDev,"/dev/",5) !=0 ) {
1078 if (NULL == d->authFile)
1079 authFile_str = "NULL";
1081 authFile_str = d->authFile;
1083 Debug("(New StartDisplay) d->authfile %s; authDir %s\n",
1084 authFile_str, authDir);
1087 * make sure stderr is pointing to the current error log file...
1093 if (!nofork_session)
1099 switch (pid = fork ())
1104 if (!nofork_session) {
1106 signal (SIGPIPE, SIG_IGN);
1110 signal (SIGPIPE, SIG_IGN);
1114 * set global display name for Debug()
1122 strncpy(p, d->name, sizeof(DisplayName) - 1);
1123 DisplayName[sizeof(DisplayName)-1] = '\0';
1125 if ( (s = strchr(p,':')) != NULL )
1126 if ( (t = strchr(p,'.')) != NULL )
1131 SetAuthorization (d);
1134 * do process accounting...
1138 char *line = (d->displayType.location==Local)
1139 ? d->gettyLine : d->name;
1140 #ifdef DEF_NETWORK_DEV
1141 if (d->displayType.location != Local &&
1142 networkDev && !strncmp(networkDev,"/dev/",5))
1146 struct stat devinfo;
1147 devname = networkDev; /* networkDev resource */
1149 devexists = (lstat(devname,&devinfo)==0);
1151 if (!devexists && (MK_NETWORK_DEV(devname) < 0)) {
1152 Debug("Creation of file '%s' failed:\n %s (%d)\n",
1153 devname,strerror(errno),errno);
1156 for (line=devname; *line; line++);
1157 while (line>devname && *line!='/') line--;
1158 if (*line=='/') line++;
1160 Debug("Using pseudo-tty %s; line=%s\n",
1165 #if !defined(CSRG_BASED)
1166 Account(d, "LOGIN", line, getpid(), LOGIN_PROCESS, status);
1170 if (!WaitForServer (d))
1171 exit (OPENFAILED_DISPLAY);
1174 * start the fallback console, if the display is local..
1176 * if the display is remote, fbconsole should be started on
1180 if (d->displayType.location==Local) {
1181 if (d->authFile && strlen(d->authFile) > 0 ) {
1182 strcpy(buff, "XAUTHORITY=");
1183 strcat(buff, d->authFile);
1186 sprintf(start_fbconsole,"%s -d %s &",FBCONSOLE, d->name);
1188 if(system(start_fbconsole) == -1)
1189 Debug("Failed to start the fallback console - %s\n",FBCONSOLE);
1197 exit (REMANAGE_DISPLAY);
1201 Debug ("Child manager process started for %s. pid = %d\n",
1204 d->status = running;
1211 TerminateProcess(int pid, int sig )
1215 kill (pid, SIGCONT);
1220 * transition from running to zombie, suspended, or deleted
1224 StopDisplay( struct display *d )
1228 bzero(&status, sizeof(waitType));
1229 Debug("StopDisplay(): %s, server pid = %d, manager pid = %d, dt_shutdown = %d\n",
1230 d->name, d->serverPid, d->pid, dt_shutdown);
1232 if (d->serverPid != -1)
1233 /* don't remove the console */
1234 if ((d->displayType.location == Local) && !dt_shutdown )
1235 d->status = suspended;
1237 d->status = zombie; /* be careful about race conditions */
1240 TerminateProcess (d->pid, SIGTERM);
1242 if (d->serverPid != -1) {
1243 TerminateProcess (d->serverPid, d->termSignal);
1247 int translate=TR_ASCII;
1249 Debug ("Resetting keyboard\n");
1251 if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) {
1252 Debug("/dev/kbd open failed\n");
1253 } else if (ioctl(kbd_fd, KIOCTRANS, (caddr_t) &translate)) {
1254 Debug("Could not set /dev/kbd back to ASCII mode\n");
1260 if ((d->displayType.location == Local) || !dt_shutdown ) {
1261 /* don't remove the console */
1262 #if !defined(CSRG_BASED)
1263 Account(d, NULL, NULL, 0, DEAD_PROCESS, status);
1271 * transition from running to phoenix or notRunning
1275 RestartDisplay( struct display *d, int forceReserver )
1277 if (d->serverPid != -1 && (forceReserver || d->terminateServer))
1279 TerminateProcess (d->serverPid, d->termSignal);
1280 d->status = phoenix;
1284 d->status = notRunning;
1288 static FD_TYPE CloseMask;
1292 RegisterCloseOnFork( int fd )
1294 FD_SET (fd, &CloseMask);
1299 #if 0 /* utility routine: activate if needed... */
1303 FD_CLR (fd, &CloseMask);
1306 if (FD_ISSET (fd, &CloseMask))
1317 for (fd = 0; fd <= max; fd++)
1318 if (FD_ISSET (fd, &CloseMask))
1320 FD_ZERO (&CloseMask);
1325 static FILE *pidFilePtr;
1332 if (pidFile && pidFile[0] != '\0') {
1333 pidFd = open (pidFile, 2);
1334 if (pidFd == -1 && errno == ENOENT)
1337 * HP OSF/1 will not allow an fdopen
1338 * of a file descriptor handed back by creat(2).
1339 * The workaround is to close the created file, and
1340 * open it Read/Write. This will be transparent to HP-UX.
1342 pidFd = creat (pidFile, 0644);
1346 pidFd = open (pidFile, 2);
1348 if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+")))
1350 LogError ((unsigned char *)"Process ID file %s cannot be opened\n",
1354 if (fscanf (pidFilePtr, "%ld", &oldpid) != 1)
1356 fseek (pidFilePtr, 0l, 0);
1359 #if defined (SYSV) || defined (SVR4)
1360 if (lockf (pidFd, F_TLOCK, 0) == -1)
1362 if ((errno == EAGAIN) || (errno == EACCES))
1368 if (flock (pidFd, LOCK_EX|LOCK_NB) == -1)
1370 if (errno == EWOULDBLOCK)
1379 * HPUX releases the lock on ANY close of the file, not just the
1380 * one that established the lock. -prr
1382 /* close(creat(pidFile, 0644)); */
1384 (void) creat(pidFile, 0644);
1385 fprintf (pidFilePtr, "%ld\n", (long)getpid ());
1386 (void) fflush(pidFilePtr);
1387 RegisterCloseOnFork(pidFd);
1393 UnlockPidFile( void )
1396 #if defined (SYSV) || defined (SVR4)
1397 lockf (pidFd, F_ULOCK, 0);
1399 flock (pidFd, LOCK_UN);
1402 fclose (pidFilePtr);
1412 int left = TitleLen;
1419 while (s = va_arg (args, char *))
1421 while (*s && left > 0)
1438 SetTitle( char *name, char *ptr )
1446 * remove domain qualifiers and screens from name...
1449 if ( (p = malloc(strlen(name) + 1)) == NULL) return 0;
1452 if ( (s = strchr(p,':')) == NULL ) {
1457 if ( (t = strchr(s,'.')) != NULL )
1460 if ( (t = strchr(p,'.')) != NULL )
1464 * if there is enough room shift program name to left,
1465 * then append display name in remaining space.
1471 t = strrchr(s, '/');
1472 if ( (t != NULL) && ((t-s+1) >= (strlen(p) + 3)) ) {
1475 strcpy(s,t); /* "program" */
1476 strcat(s," <"); /* "program <" */
1477 strcat(s,p); /* "program <displayName" */
1478 strcat(s,">"); /* "program <displayName>" */
1481 length = length - strlen(s);
1494 /*****************************************************************************
1497 * Start a "getty" running on the console...
1499 *****************************************************************************/
1501 #if defined (_AIX) && defined (_POWER) || defined (__osf__)
1502 #define GETTYPATH "/usr/sbin/getty"
1503 #elif defined(__OpenBSD__)
1504 #define GETTYPATH "/usr/libexec/getty"
1505 #elif defined(__linux)
1506 #define GETTYPATH "/sbin/getty"
1507 #elif !defined (__apollo)
1508 #define GETTYPATH "/etc/getty"
1512 StartGetty( struct display *d )
1518 Debug ("StartGetty(): %s\n", d->name);
1520 bzero(&status, sizeof(waitType));
1522 * ensure that server is known dead...
1527 #if !defined(GETTYPATH)
1532 * check to see if we have a valid device (at least a non-null name)...
1535 if ( d->gettyLine &&
1536 (strlen(d->gettyLine) > 0) &&
1537 (strcmp(d->gettyLine,"??") != 0) )
1544 * if there is already a getty running on the device, set up
1545 * to start watching it. When it exits, restart the server...
1548 if ( GettyRunning(d) ) {
1549 d->status = suspended; /* set up to restart server */
1550 wakeupTime = 0; /* enable polling */
1552 sleep(1); /* wait for fbconsole to go away */
1553 GettyMessage(d,1); /* print a help message */
1560 * there is no getty running on the device, try to start one...
1563 d->status = phoenix; /* set up to restart server */
1566 switch (pid = fork ()) {
1571 * do process accounting...
1573 #if !defined(CSRG_BASED)
1574 Account(d, "LOGIN", NULL, getpid(), LOGIN_PROCESS, status);
1579 /* The tty argument for getty on AIX must be of the form "/dev/any tty"
1580 and so the following logic
1581 Raghu krovvidi 07.07.93
1583 strcpy(tynm,"/dev/");
1584 strcat(tynm,d->gettyLine);
1586 strcpy(tynm, d->gettyLine);
1589 Debug(" execing getty on %s\n",tynm);
1590 execl(GETTYPATH, "getty", tynm, d->gettySpeed, (char *)0);
1591 LogError ((unsigned char *)"Can not execute %s for %s: errno = %d\n",
1592 GETTYPATH, d->name, errno);
1594 exit (UNMANAGE_DISPLAY);
1597 Debug ("Fork of /etc/getty failed %s\n", d->name);
1598 LogError ((unsigned char *)"Can not fork to execute /etc/getty %s\n", d->name);
1605 Debug ("/etc/getty started on %s\n", d->name);
1608 #endif /* GETTYPATH not defined */
1612 /***************************************************************************
1616 * Print a message on the display device when going into No Windows mode.
1618 ***************************************************************************/
1621 GettyMessage( struct display *d, int msgnum )
1628 snprintf(buf, sizeof(buf), "/dev/%s", d->gettyLine);
1630 if ( (tf = fopen (buf, "a")) != NULL) {
1632 "\r\n\r\n*****************************************************************************\r\n*\r\n");
1637 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_SUS1_LABEL,MC_DEF_SUS1_LABEL));
1639 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_SUS2_LABEL,MC_DEF_SUS2_LABEL));
1641 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_SUS3_LABEL,MC_DEF_SUS3_LABEL));
1647 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_RES_LABEL,MC_DEF_RES_LABEL));
1654 (char *)ReadCatalog(MC_LABEL_SET,MC_START_LBLDPY,MC_DEF_START_LBLDPY),
1657 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_WAIT_LABEL,MC_DEF_WAIT_LABEL));
1663 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_X_LABEL,MC_DEF_X_LABEL),
1671 "*****************************************************************************\r\n");
1679 /***************************************************************************
1683 * See if a getty process is running against the display device. This
1684 * routine may need to be rewritten on other platforms if a different
1685 * mechanism is needed to make the determination.
1687 * Output: TRUE == a login process is active on the requested device
1688 * FALSE == a login process is not active on the device.
1690 * Sets d->gettyState:
1691 * NONE - no getty running or don't care
1692 * LOGIN - getty running
1693 * USER - user logged in on getty
1695 * Note: The check for a getty process running is made by scanning
1696 * /etc/utmp, looking for a login process on the respective device.
1697 * However, the child Dtlogin spawned by the master Dtlogin to
1698 * handle this display also is a "login process" according to
1699 * /etc/utmp. It provides a login path and therefore must register
1700 * itself as so. If a getty is also running, there are actually two
1701 * login processes running against the same device at the same time.
1703 * The child Dtlogin dies before the scan of /etc/utmp is made.
1704 * Provided /etc/utmp is updated correctly, the Dtlogin entry will
1705 * be marked as dead and will not show up in the scan of /etc/utmp.
1706 ***************************************************************************/
1709 GettyRunning( struct display *d )
1711 #if defined(__FreeBSD__) && OSMAJORVERSION > 8
1712 struct utmpx utmp; /* local struct for new entry */
1713 struct utmpx *u; /* pointer to entry in utmp file */
1715 struct utmp utmp; /* local struct for new entry */
1716 struct utmp *u; /* pointer to entry in utmp file */
1719 int rvalue; /* return value (TRUE or FALSE) */
1722 d->gettyState = DM_GETTY_NONE;
1725 * check to see if we have a valid device (at least a non-null name)...
1728 if ( d->gettyLine &&
1729 (strlen(d->gettyLine) > 0) &&
1730 (strcmp(d->gettyLine,"??") != 0) )
1736 #if defined(__FreeBSD__) && OSMAJORVERSION > 8
1737 bzero(&utmp, sizeof(struct utmpx));
1739 bzero(&utmp, sizeof(struct utmp));
1743 if (!strcmp(d->gettyLine,"console")) {
1747 fd = open("/dev/console",O_RDONLY);
1748 ttynm = ttyname(fd);
1750 strcpy(utmp.ut_line,ttynm);
1755 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line) - 1);
1756 utmp.ut_line[sizeof(utmp.ut_line) - 1] = 0;
1760 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line) - 1);
1761 utmp.ut_line[sizeof(utmp.ut_line) - 1] = 0;
1764 Debug("Checking for a getty on line %s.\n", utmp.ut_line);
1766 #if !defined(CSRG_BASED)
1771 while ( (u = getutent()) != NULL ) {
1773 if ((strncmp(u->ut_line, utmp.ut_line, sizeof(u->ut_line)) != 0) ||
1774 (strncmp(u->ut_id, d->utmpId, sizeof(u->ut_id)) == 0) )
1777 switch (u->ut_type) {
1779 case INIT_PROCESS: strcpy(buf, "INIT_PROCESS"); break;
1780 case LOGIN_PROCESS: strcpy(buf, "LOGIN_PROCESS"); break;
1781 case USER_PROCESS: strcpy(buf, "USER_PROCESS"); break;
1782 case DEAD_PROCESS: strcpy(buf, "DEAD_PROCESS"); break;
1783 default: strcpy(buf, "UNKNOWN"); break;
1786 Debug("Utmp info: id=%.4s, user=%s, line=%s, pid=%d, type=%s\n",
1787 u->ut_id, u->ut_user, u->ut_line, u->ut_pid, buf);
1789 if ( u->ut_type == INIT_PROCESS || u->ut_type == LOGIN_PROCESS) {
1790 d->gettyState = DM_GETTY_LOGIN;
1792 else if (wakeupTime <= 0 && u->ut_type == USER_PROCESS) {
1793 d->gettyState = DM_GETTY_USER;
1796 if (d->gettyState != DM_GETTY_NONE)
1804 #endif /* !CSRG_BASED */
1810 /***************************************************************************
1814 * Check if enough time has elapsed since shutdown.
1816 * This is primarily to work with /etc/shutdown. When shutdown kills
1817 * dtlogin (/etc/killall), init immediately restarts it. Shutdown kills
1818 * it again and init restarts it. At each restart, the X-server may start
1819 * on the local display and then subsequently be killed. The user sees a
1820 * flashing screen and sometimes the console is left in an unreset state.
1822 * When Dtlogin shuts down, it touches the access time on the Xservers
1823 * file. (MarkShutdownTime()). This time is then used to determine if
1824 * sufficient time has elapsed before restarting.
1826 ***************************************************************************/
1829 CheckRestartTime( void )
1834 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1836 Debug("Checking restart time.\n");
1839 /* only those other systems are this slow :-) */
1840 sleeptime = 6 - (int) (time((time_t *) 0) - statb.st_atime);
1842 sleeptime = 30 - (int) (time((time_t *) 0) - statb.st_atime);
1845 if ( sleeptime > 30 ) sleeptime = 30;
1847 if ( sleeptime > 0 ) {
1848 Debug("Restarting too soon after shutdown. Sleeping %d seconds.\n",
1857 /***************************************************************************
1861 * Save the time when we shut down to check later for too fast of a restart.
1863 ***************************************************************************/
1866 MarkShutdownTime( void )
1869 struct utimbuf timebuf;
1871 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1873 Debug("Marking shutdown time.\n");
1875 timebuf.actime = time((time_t *) 0 );
1876 timebuf.modtime = statb.st_mtime;
1878 if ( (utime(servers, &timebuf)) != 0 ) {
1879 Debug("MarkShutdownTime(): utime() error = %d\n", errno);
1885 /***************************************************************************
1889 * Make the default dt directory "/var/dt" if needed.
1891 ***************************************************************************/
1893 dtMakeDefaultDir( void )
1895 dtmkdir("/var", 0755, 0);
1896 dtmkdir("/var/dt", 0755, 1);
1897 dtmkdir("/var/dt/tmp", 0755, 1);
1898 dtmkdir("/var/dt/appconfig", 0755, 1);
1899 dtmkdir("/var/dt/appconfig/appmanager", 0755, 1);
1903 dtmkdir(char *dir, mode_t dir_mode, int force)
1905 struct stat file_status;
1907 if ( stat(dir, &file_status) != 0) {
1908 /** try to create it **/
1909 if ( mkdir(dir, dir_mode) == 0) {
1910 chmod(dir, dir_mode); /** since umask is non-zero **/
1911 Debug("Created dir %s\n", dir);
1913 LogError((unsigned char *)"Unable to create dir %s\n", dir);
1916 if ( force && (file_status.st_mode & dir_mode) != dir_mode) {
1917 /** try to set correct permissions **/
1918 if ( chmod(dir, file_status.st_mode | dir_mode) == 0) {
1919 Debug("Set permissions on %s\n", dir);
1921 LogError((unsigned char *)
1922 "Unable to set permissions on %s\n", dir);