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)
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 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
606 * make sure authorization file is deleted...
610 if (d->authorization && d->authFile) {
611 (void) unlink (d->authFile);
619 * reset "startTries" ...
621 * Local displays: Only for clean exits of the server
622 * Foreign displays: Always except for OPENFAILED_DISPLAY
624 * Note: if startTries expires and a "getty" is run on the local
625 * display, startTries will be reset to zero before
626 * attempting to restart the server.
629 switch (waitVal (status)) {
630 case OBEYSESS_DISPLAY:
631 case RESERVER_DISPLAY:
635 case OPENFAILED_DISPLAY:
639 if (d->displayType.location != Local )
648 * process exit status...
651 switch (waitVal (status)) {
652 case UNMANAGE_DISPLAY:
653 Debug ("Display exited with UNMANAGE_DISPLAY\n");
657 case OBEYSESS_DISPLAY:
658 Debug ("Display exited with (check)OBEYSESS_DISPLAY\n");
659 if (d->displayType.lifetime != Permanent || d->status == zombie)
662 RestartDisplay (d, FALSE);
666 Debug ("Display exited with unknown status %d\n", waitVal(status));
667 LogError ((unsigned char *)"Unknown session exit code %d from process %d\n",
668 waitVal (status), pid);
672 case OPENFAILED_DISPLAY:
673 Debug ("Display exited with OPENFAILED_DISPLAY\n");
674 if (d->displayType.origin == FromXDMCP)
675 SendFailed (d, "Cannot open display");
677 if (d->displayType.location != Local)
680 if (d->displayType.origin == FromXDMCP ||
681 d->status == zombie ||
682 d->startTries >= d->startAttempts)
685 RestartDisplay (d, TRUE);
689 case RESERVER_DISPLAY:
690 Debug ("Display exited with RESERVER_DISPLAY\n");
691 if (d->displayType.origin == FromXDMCP || d->status == zombie)
694 RestartDisplay (d, TRUE);
697 case waitCompose (SIGTERM,0,0):
698 Debug ("Display exited on SIGTERM\n");
699 if (d->displayType.origin == FromXDMCP || d->status == zombie)
702 RestartDisplay (d, TRUE);
705 case REMANAGE_DISPLAY:
706 Debug ("Display exited with REMANAGE_DISPLAY\n");
708 * XDMCP will restart the session if the display
711 if (d->displayType.origin == FromXDMCP || d->status == zombie)
714 RestartDisplay (d, FALSE);
717 case SUSPEND_DISPLAY:
718 Debug ("Display exited with SUSPEND_DISPLAY\n");
719 if (d->displayType.location == Local)
722 RestartDisplay (d, FALSE);
727 else if ( (d = FindDisplayByServerPid (pid)) != 0 )
732 * do process accounting...
735 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
740 Debug ("Zombie server reaped, removing display %s\n", d->name);
744 Debug ("Phoenix server arises, restarting display %s\n", d->name);
745 d->status = notRunning;
748 Debug ("Server for display %s terminated unexpectedly, status %d\n", d->name, waitVal (status));
749 LogError ((unsigned char *)"Server for display %s terminated unexpectedly %d\n",
750 d->name, waitVal(status) );
753 Debug ("Terminating session pid %d\n", d->pid);
754 TerminateProcess (d->pid, SIGTERM);
758 Debug ("Server exited for notRunning session on display %s\n", d->name);
761 Debug ("Server for display %s is suspended\n", d->name);
763 d->status = notRunning;
769 Debug ("Unknown child termination, status %d\n", waitVal (status));
774 CheckDisplayStatus( struct display *d )
777 if (d->displayType.origin == FromFile)
788 Debug("Check %s: status=%d wakeupTime=%d\n", d->name,
789 d->status, wakeupTime);
790 if (d->status == suspended && wakeupTime >= 0)
791 if ( GettyRunning(d) || (strcmp(d->gettyLine,"??") == 0))
792 if ( wakeupTime == 0 ) {
793 Debug("Polling of suspended server %s started.\n",
796 wakeupTime = (wakeupInterval < 10
798 : 2 * wakeupInterval );
801 Debug("Polling of suspended server %s stopped.\n",
803 wakeupTime = -1; /* disable polling */
804 d->status = notRunning; /* restart server */
806 if ( !dt_shutdown ) GettyMessage(d,2);
809 Debug("Polling of suspended server %s continued.\n",
811 wakeupTime = wakeupInterval; /* continue polling*/
814 if (d->status == notRunning)
822 StartDisplays( void )
824 ForEachDisplay (CheckDisplayStatus);
834 char start_fbconsole[1024];
837 Debug ("StartDisplay(): %s\n", d->name);
839 bzero(&status, sizeof(waitType));
840 if (d->authFile == NULL)
841 authFile_str = "NULL";
843 authFile_str = d->authFile;
845 Debug("(Old StartDisplay) d->authfile %s; authDir %s\n",
846 authFile_str, authDir);
849 * The following call to RemoveDisplay is to catch race conditions during
850 * shutdown. There is no point in starting a display if Dtlogin is in the
851 * process of shutting down...
853 if (d->displayType.origin == FromFile && dt_shutdown ) {
859 /* make a backup of the authFile before loading resources and */
860 /* copy it back to authFile field od display structure for X server */
861 /* to reread the host database list on reset */
867 strcpy(bkup ,d->authFile);
869 LoadDisplayResources (d);
871 /* The Xserver may NOT have been killed, so reuse the authFile. */
872 if (NULL == d->authFile &&
874 0 == strncmp(authDir, bkup, strlen(authDir)))
875 d->authFile= (char *) strdup(bkup);
877 if (d->authFile == NULL)
878 authFile_str = "NULL";
880 authFile_str = d->authFile;
882 Debug("(Mid StartDisplay) d->authfile %s; authDir %s; bkup %s\n",
883 authFile_str, authDir, bkup);
886 if (d->displayType.location == Local)
888 /* don't bother pinging local displays; we'll
889 * certainly notice when they exit
894 Debug ("SetLocalAuthorization %s, auth %s\n",
895 d->name, d->authNames);
897 SetLocalAuthorization (d);
900 * reset the server after writing the authorization information
901 * to make it read the file (for compatibility with old
902 * servers which read auth file only on reset instead of
903 * at first connection)
905 if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
906 kill (d->serverPid, d->resetSignal);
911 * initialize d->utmpId. Check to see if anyone else is using
912 * the requested ID. Always allow the first request for "dt" to
913 * succeed as utmp may have become corrupted.
916 if (d->utmpId == NULL) {
917 static int firsttime = 1;
918 static char letters[] = "0123456789abcdefghijklmnopqrstuvwxyzz";
921 d->utmpId = malloc(5);
922 strcpy(d->utmpId, UTMPREC_PREFIX);
928 if ( firsttime || UtmpIdOpen(d->utmpId)) {
933 strncpy(&(d->utmpId[strlen(d->utmpId)]), t++, 1);
935 } while (*t != NULL);
938 Debug ("All DT utmp IDs already in use. Removing display %s\n",
940 LogError ((unsigned char *)"All DT utmp IDs already in use. Removing display %s\n",
949 * set d->gettyLine to "console" for display ":0" if it is not
953 if (! d->gettyLine || strlen(d->gettyLine) == 0 ) {
956 if ( (p = index(d->name,':')) != NULL &&
957 ( strncmp(++p,"0",1) == 0 )) {
959 d->gettyLine = (char *) malloc(8);
960 strcpy(d->gettyLine, "console");
963 d->gettyLine = (char *) malloc(3);
964 strcpy(d->gettyLine, "??");
970 * if gettyLine is set to "console", set gettySpeed to "console" also
973 if (d->gettyLine && (strcmp(d->gettyLine, "console") == 0 ) ) {
975 free((char *) d->gettySpeed);
977 d->gettySpeed = (char *) malloc(8);
979 strcpy(d->gettySpeed, "console");
984 * start server. If it cannot be started and this is the console,
988 Debug("Attempting to start server for %s. startTries = %d\n",
989 d->name, d->startTries);
991 if (d->serverPid == -1) {
992 static int bootup = 0;
994 while (bootup++ < 5) {
995 if (GettyRunning(d)) {
1006 if (d->serverPid == -1 &&
1007 (d->startTries++ >= d->startAttempts ||
1010 LogError ((unsigned char *)"Server for display %s can't be started.\n", d->name);
1023 /* this will only happen when using XDMCP */
1024 if (d->authorizations)
1025 SaveServerAuthorizations (d, d->authorizations, d->authNum);
1028 * Generate a utmp ID address for a foreign display. Use the last
1029 * four characters of the DISPLAY name, shifting left if they
1030 * are already in use...
1033 if (d->utmpId == NULL) {
1038 d->utmpId = malloc(sizeof(u->ut_id) +1);
1040 i = strlen (d->name);
1041 if (i >= sizeof (u->ut_id))
1042 i -= sizeof (u->ut_id);
1046 for ( p = d->name, q = d->name + i; p <= q; q-- ) {
1047 (void) strncpy (d->utmpId, q, sizeof (u->ut_id));
1048 d->utmpId[sizeof(u->ut_id)] = '\0';
1049 if (UtmpIdOpen(d->utmpId))
1053 #ifdef DEF_NETWORK_DEV
1055 * If "networkDev" does not start with "/dev/" then foreign
1056 * accounting is turned off. Return utmpId to NULL.
1058 if (networkDev && strncmp(networkDev,"/dev/",5) !=0 ) {
1066 if (NULL == d->authFile)
1067 authFile_str = "NULL";
1069 authFile_str = d->authFile;
1071 Debug("(New StartDisplay) d->authfile %s; authDir %s\n",
1072 authFile_str, authDir);
1075 * make sure stderr is pointing to the current error log file...
1081 if (!nofork_session)
1087 switch (pid = fork ())
1092 if (!nofork_session) {
1094 signal (SIGPIPE, SIG_IGN);
1098 signal (SIGPIPE, SIG_IGN);
1102 * set global display name for Debug()
1110 strncpy(p, d->name, sizeof(DisplayName));
1111 DisplayName[sizeof(DisplayName)-1] = '\0';
1113 if ( (s = strchr(p,':')) != NULL )
1114 if ( (t = strchr(p,'.')) != NULL )
1119 SetAuthorization (d);
1122 * do process accounting...
1126 char *line = (d->displayType.location==Local)
1127 ? d->gettyLine : d->name;
1128 #ifdef DEF_NETWORK_DEV
1129 if (d->displayType.location != Local &&
1130 networkDev && !strncmp(networkDev,"/dev/",5))
1134 struct stat devinfo;
1135 devname = networkDev; /* networkDev resource */
1137 devexists = (lstat(devname,&devinfo)==0);
1139 if (!devexists && (MK_NETWORK_DEV(devname) < 0)) {
1140 Debug("Creation of file '%s' failed:\n %s (%d)\n",
1141 devname,strerror(errno),errno);
1144 for (line=devname; *line; line++);
1145 while (line>devname && *line!='/') line--;
1146 if (*line=='/') line++;
1148 Debug("Using pseudo-tty %s; line=%s\n",
1153 Account(d, "LOGIN", line, getpid(), LOGIN_PROCESS, status);
1156 if (!WaitForServer (d))
1157 exit (OPENFAILED_DISPLAY);
1160 * start the fallback console, if the display is local..
1162 * if the display is remote, fbconsole should be started on
1166 if (d->displayType.location==Local) {
1167 if (d->authFile && strlen(d->authFile) > 0 ) {
1168 strcpy(buff, "XAUTHORITY=");
1169 strcat(buff, d->authFile);
1172 sprintf(start_fbconsole,"%s -d %s &",FBCONSOLE, d->name);
1174 if(system(start_fbconsole) == -1)
1175 Debug("Failed to start the fallback console - %s\n",FBCONSOLE);
1183 exit (REMANAGE_DISPLAY);
1187 Debug ("Child manager process started for %s. pid = %d\n",
1190 d->status = running;
1196 TerminateProcess(int pid, int sig )
1200 kill (pid, SIGCONT);
1205 * transition from running to zombie, suspended, or deleted
1209 StopDisplay( struct display *d )
1213 bzero(&status, sizeof(waitType));
1214 Debug("StopDisplay(): %s, server pid = %d, manager pid = %d, dt_shutdown = %d\n",
1215 d->name, d->serverPid, d->pid, dt_shutdown);
1217 if (d->serverPid != -1)
1218 /* don't remove the console */
1219 if ((d->displayType.location == Local) && !dt_shutdown )
1220 d->status = suspended;
1222 d->status = zombie; /* be careful about race conditions */
1225 TerminateProcess (d->pid, SIGTERM);
1227 if (d->serverPid != -1) {
1228 TerminateProcess (d->serverPid, d->termSignal);
1232 int translate=TR_ASCII;
1234 Debug ("Resetting keyboard\n");
1236 if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) {
1237 Debug("/dev/kbd open failed\n");
1238 } else if (ioctl(kbd_fd, KIOCTRANS, (caddr_t) &translate)) {
1239 Debug("Could not set /dev/kbd back to ASCII mode\n");
1245 if ((d->displayType.location == Local) || !dt_shutdown ) {
1246 /* don't remove the console */
1247 Account(d, NULL, NULL, 0, DEAD_PROCESS, status);
1254 * transition from running to phoenix or notRunning
1258 RestartDisplay( struct display *d, int forceReserver )
1260 if (d->serverPid != -1 && (forceReserver || d->terminateServer))
1262 TerminateProcess (d->serverPid, d->termSignal);
1263 d->status = phoenix;
1267 d->status = notRunning;
1271 static FD_TYPE CloseMask;
1275 RegisterCloseOnFork( int fd )
1277 FD_SET (fd, &CloseMask);
1282 #if 0 /* utility routine: activate if needed... */
1286 FD_CLR (fd, &CloseMask);
1289 if (FD_ISSET (fd, &CloseMask))
1300 for (fd = 0; fd <= max; fd++)
1301 if (FD_ISSET (fd, &CloseMask))
1303 FD_ZERO (&CloseMask);
1308 static FILE *pidFilePtr;
1315 if (pidFile && pidFile[0] != '\0') {
1316 pidFd = open (pidFile, 2);
1317 if (pidFd == -1 && errno == ENOENT)
1320 * HP OSF/1 will not allow an fdopen
1321 * of a file descriptor handed back by creat(2).
1322 * The workaround is to close the created file, and
1323 * open it Read/Write. This will be transparent to HP-UX.
1325 pidFd = creat (pidFile, 0644);
1327 pidFd = open (pidFile, 2);
1329 if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+")))
1331 LogError ((unsigned char *)"Process ID file %s cannot be opened\n",
1335 if (fscanf (pidFilePtr, "%ld", &oldpid) != 1)
1337 fseek (pidFilePtr, 0l, 0);
1340 #if defined (SYSV) || defined (SVR4)
1341 if (lockf (pidFd, F_TLOCK, 0) == -1)
1343 if ((errno == EAGAIN) || (errno == EACCES))
1349 if (flock (pidFd, LOCK_EX|LOCK_NB) == -1)
1351 if (errno == EWOULDBLOCK)
1360 * HPUX releases the lock on ANY close of the file, not just the
1361 * one that established the lock. -prr
1363 /* close(creat(pidFile, 0644)); */
1365 (void) creat(pidFile, 0644);
1366 fprintf (pidFilePtr, "%ld\n", (long)getpid ());
1367 (void) fflush(pidFilePtr);
1368 RegisterCloseOnFork(pidFd);
1374 UnlockPidFile( void )
1377 #if defined (SYSV) || defined (SVR4)
1378 lockf (pidFd, F_ULOCK, 0);
1380 flock (pidFd, LOCK_UN);
1383 fclose (pidFilePtr);
1393 int left = TitleLen;
1400 while (s = va_arg (args, char *))
1402 while (*s && left > 0)
1419 SetTitle( char *name, char *ptr )
1427 * remove domain qualifiers and screens from name...
1430 if ( (p = malloc(strlen(name) + 1)) == NULL) return;
1433 if ( (s = strchr(p,':')) == NULL ) {
1438 if ( (t = strchr(s,'.')) != NULL )
1441 if ( (t = strchr(p,'.')) != NULL )
1445 * if there is enough room shift program name to left,
1446 * then append display name in remaining space.
1452 t = strrchr(s, '/');
1453 if ( (t != NULL) && ((t-s+1) >= (strlen(p) + 3)) ) {
1456 strcpy(s,t); /* "program" */
1457 strcat(s," <"); /* "program <" */
1458 strcat(s,p); /* "program <displayName" */
1459 strcat(s,">"); /* "program <displayName>" */
1462 length = length - strlen(s);
1474 /*****************************************************************************
1477 * Start a "getty" running on the console...
1479 *****************************************************************************/
1481 #if defined (_AIX) && defined (_POWER) || defined (__osf__)
1482 #define GETTYPATH "/usr/sbin/getty"
1483 #elif !defined (__apollo)
1484 #define GETTYPATH "/etc/getty"
1488 StartGetty( struct display *d )
1494 Debug ("StartGetty(): %s\n", d->name);
1496 bzero(&status, sizeof(waitType));
1498 * ensure that server is known dead...
1503 #if !defined(GETTYPATH)
1508 * check to see if we have a valid device (at least a non-null name)...
1511 if ( d->gettyLine &&
1512 (strlen(d->gettyLine) > 0) &&
1513 (strcmp(d->gettyLine,"??") != 0) )
1520 * if there is already a getty running on the device, set up
1521 * to start watching it. When it exits, restart the server...
1524 if ( GettyRunning(d) ) {
1525 d->status = suspended; /* set up to restart server */
1526 wakeupTime = 0; /* enable polling */
1528 sleep(1); /* wait for fbconsole to go away */
1529 GettyMessage(d,1); /* print a help message */
1536 * there is no getty running on the device, try to start one...
1539 d->status = phoenix; /* set up to restart server */
1542 switch (pid = fork ()) {
1547 * do process accounting...
1549 Account(d, "LOGIN", NULL, getpid(), LOGIN_PROCESS, status);
1553 /* The tty argument for getty on AIX must be of the form "/dev/any tty"
1554 and so the following logic
1555 Raghu krovvidi 07.07.93
1557 strcpy(tynm,"/dev/");
1558 strcat(tynm,d->gettyLine);
1560 strcpy(tynm, d->gettyLine);
1563 Debug(" execing getty on %s\n",tynm);
1564 execl(GETTYPATH, "getty", tynm, d->gettySpeed, (char *)0);
1565 LogError ((unsigned char *)"Can not execute %s for %s: errno = %d\n",
1566 GETTYPATH, d->name, errno);
1568 exit (UNMANAGE_DISPLAY);
1571 Debug ("Fork of /etc/getty failed %s\n", d->name);
1572 LogError ((unsigned char *)"Can not fork to execute /etc/getty %s\n", d->name);
1579 Debug ("/etc/getty started on %s\n", d->name);
1582 #endif /* GETTYPATH not defined */
1586 /***************************************************************************
1590 * Print a message on the display device when going into No Windows mode.
1592 ***************************************************************************/
1595 GettyMessage( struct display *d, int msgnum )
1600 strcpy(buf,"/dev/");
1601 strcat(buf,d->gettyLine);
1603 if ( (tf = fopen (buf, "a")) != NULL) {
1605 "\r\n\r\n*****************************************************************************\r\n*\r\n");
1610 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS1_LABEL,MC_DEF_SUS1_LABEL));
1612 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS2_LABEL,MC_DEF_SUS2_LABEL));
1614 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS3_LABEL,MC_DEF_SUS3_LABEL));
1620 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_RES_LABEL,MC_DEF_RES_LABEL));
1627 (char *)ReadCatalog(MC_LABEL_SET,MC_START_LBLDPY,MC_DEF_START_LBLDPY),
1630 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_WAIT_LABEL,MC_DEF_WAIT_LABEL));
1636 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_X_LABEL,MC_DEF_X_LABEL),
1644 "*****************************************************************************\r\n");
1652 /***************************************************************************
1656 * See if a getty process is running against the display device. This
1657 * routine may need to be rewritten on other platforms if a different
1658 * mechanism is needed to make the determination.
1660 * Output: TRUE == a login process is active on the requested device
1661 * FALSE == a login process is not active on the device.
1663 * Sets d->gettyState:
1664 * NONE - no getty running or don't care
1665 * LOGIN - getty running
1666 * USER - user logged in on getty
1668 * Note: The check for a getty process running is made by scanning
1669 * /etc/utmp, looking for a login process on the respective device.
1670 * However, the child Dtlogin spawned by the master Dtlogin to
1671 * handle this display also is a "login process" according to
1672 * /etc/utmp. It provides a login path and therefore must register
1673 * itself as so. If a getty is also running, there are actually two
1674 * login processes running against the same device at the same time.
1676 * The child Dtlogin dies before the scan of /etc/utmp is made.
1677 * Provided /etc/utmp is updated correctly, the Dtlogin entry will
1678 * be marked as dead and will not show up in the scan of /etc/utmp.
1679 ***************************************************************************/
1682 GettyRunning( struct display *d )
1684 struct utmp utmp; /* local struct for new entry */
1685 struct utmp *u; /* pointer to entry in utmp file */
1687 int rvalue; /* return value (TRUE or FALSE) */
1690 d->gettyState = DM_GETTY_NONE;
1693 * check to see if we have a valid device (at least a non-null name)...
1696 if ( d->gettyLine &&
1697 (strlen(d->gettyLine) > 0) &&
1698 (strcmp(d->gettyLine,"??") != 0) )
1704 bzero(&utmp, sizeof(struct utmp));
1707 if (!strcmp(d->gettyLine,"console")) {
1711 fd = open("/dev/console",O_RDONLY);
1712 ttynm = ttyname(fd);
1714 strcpy(utmp.ut_line,ttynm);
1718 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1721 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1724 Debug("Checking for a getty on line %s.\n", utmp.ut_line);
1730 while ( (u = getutent()) != NULL ) {
1732 if ((strncmp(u->ut_line, utmp.ut_line, sizeof(u->ut_line)) != 0) ||
1733 (strncmp(u->ut_id, d->utmpId, sizeof(u->ut_id)) == 0) )
1736 switch (u->ut_type) {
1738 case INIT_PROCESS: strcpy(buf, "INIT_PROCESS"); break;
1739 case LOGIN_PROCESS: strcpy(buf, "LOGIN_PROCESS"); break;
1740 case USER_PROCESS: strcpy(buf, "USER_PROCESS"); break;
1741 case DEAD_PROCESS: strcpy(buf, "DEAD_PROCESS"); break;
1742 default: strcpy(buf, "UNKNOWN"); break;
1745 Debug("Utmp info: id=%.4s, user=%s, line=%s, pid=%d, type=%s\n",
1746 u->ut_id, u->ut_user, u->ut_line, u->ut_pid, buf);
1748 if ( u->ut_type == INIT_PROCESS || u->ut_type == LOGIN_PROCESS) {
1749 d->gettyState = DM_GETTY_LOGIN;
1751 else if (wakeupTime <= 0 && u->ut_type == USER_PROCESS) {
1752 d->gettyState = DM_GETTY_USER;
1755 if (d->gettyState != DM_GETTY_NONE)
1768 /***************************************************************************
1772 * Check if enough time has elapsed since shutdown.
1774 * This is primarily to work with /etc/shutdown. When shutdown kills
1775 * dtlogin (/etc/killall), init immediately restarts it. Shutdown kills
1776 * it again and init restarts it. At each restart, the X-server may start
1777 * on the local display and then subsequently be killed. The user sees a
1778 * flashing screen and sometimes the console is left in an unreset state.
1780 * When Dtlogin shuts down, it touches the access time on the Xservers
1781 * file. (MarkShutdownTime()). This time is then used to determine if
1782 * sufficient time has elapsed before restarting.
1784 ***************************************************************************/
1787 CheckRestartTime( void )
1792 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1794 Debug("Checking restart time.\n");
1797 /* only those other systems are this slow :-) */
1798 sleeptime = 6 - (int) (time((time_t *) 0) - statb.st_atime);
1800 sleeptime = 30 - (int) (time((time_t *) 0) - statb.st_atime);
1803 if ( sleeptime > 30 ) sleeptime = 30;
1805 if ( sleeptime > 0 ) {
1806 Debug("Restarting too soon after shutdown. Sleeping %d seconds.\n",
1815 /***************************************************************************
1819 * Save the time when we shut down to check later for too fast of a restart.
1821 ***************************************************************************/
1824 MarkShutdownTime( void )
1827 struct utimbuf timebuf;
1829 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1831 Debug("Marking shutdown time.\n");
1833 timebuf.actime = time((time_t *) 0 );
1834 timebuf.modtime = statb.st_mtime;
1836 if ( (utime(servers, &timebuf)) != 0 ) {
1837 Debug("MarkShutdownTime(): utime() error = %d\n", errno);
1843 /***************************************************************************
1847 * Make the default dt directory "/var/dt" if needed.
1849 ***************************************************************************/
1851 dtMakeDefaultDir( void )
1853 dtmkdir("/var", 0775);
1854 dtmkdir("/var/dt", 0755);
1855 dtmkdir("/var/dt/tmp", 0755);
1856 dtmkdir("/var/dt/appconfig", 0755);
1857 dtmkdir("/var/dt/appconfig/appmanager", 0755);
1861 dtmkdir(char *dir, mode_t dir_mode)
1863 struct stat file_status;
1865 if ( stat(dir, &file_status) != 0) {
1866 /** try to create it **/
1867 if ( mkdir(dir, dir_mode) == 0) {
1868 chmod(dir, dir_mode); /** since umask is non-zero **/
1869 Debug("Created dir %s\n", dir);
1871 LogError((unsigned char *)"Unable to create dir %s\n", dir);
1874 if ( (file_status.st_mode & dir_mode) != dir_mode) {
1875 /** try to set correct permissions **/
1876 if ( chmod(dir, file_status.st_mode | dir_mode) == 0) {
1877 Debug("Set permissions on %s\n", dir);
1879 LogError((unsigned char *)
1880 "Unable to set permissions on %s\n", dir);