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)))
88 /***************************************************************************
90 * Local procedure declarations
92 ***************************************************************************/
94 static void CheckDisplayStatus( struct display *d) ;
95 static void CheckRestartTime( void ) ;
96 static void ChildNotify( int arg ) ;
97 static void MarkDisplay( struct display *d) ;
98 static void KillDisplay( struct display *d) ;
99 static void MarkShutdownTime( void ) ;
100 static void ProcessChildDeath( int pid, waitType status) ;
101 static void RescanIfMod( void ) ;
102 static void RescanNotify( int arg ) ;
103 static void RescanServers( void ) ;
104 static void RestartDisplay( struct display *d, int forceReserver) ;
105 static int ScanServers( void ) ;
106 static void SetAccessFileTime( void ) ;
107 static void SetConfigFileTime( void ) ;
108 static int StartGetty( struct display *d) ;
109 static void StopAll( int arg ) ;
110 static long StorePid( void ) ;
111 static void TerminateProcess( int pid, int sig) ;
112 static void UnlockPidFile( void ) ;
113 static void dtMakeDefaultDir( void );
114 static void dtmkdir(char *dir, mode_t dir_mode, int force);
119 /***************************************************************************
123 ***************************************************************************/
124 struct passwd puser; /* pseudo-user password entry */
127 static long ServersModTime, ConfigModTime, AccessFileModTime;
131 char DisplayName[32]="main";
134 int nofork_session = 0;
138 char *Title; /* Global argv[0] */
142 static int parent_pid = -1; /* PID of parent dtlogin process */
145 /***************************************************************************/
148 main( int argc, char **argv )
152 struct passwd *p; /* pointer to passwd structure (pwd.h) */
155 * make sure at least world write access is disabled...
157 if ( (oldumask = umask(022) & 002) == 002)
158 (void) umask(oldumask);
162 TitleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - Title;
167 * save program name and path...
170 if ( (progName = malloc(strlen(argv[0]) + 1)) != NULL )
171 strcpy(progName, argv[0]);
175 * Step 1 - load configuration parameters
177 InitResources (argc, argv);
178 SetConfigFileTime ();
181 * Only allow root to run xdm to avoid problems (HP 700/X version)
183 if (debugLevel == 0 && getuid() != 0)
186 (char *)ReadCatalog(MC_ERROR_SET,MC_BAD_ROOT,MC_DEF_BAD_ROOT),
191 dtMakeDefaultDir(); /** Create /var/dt if needed **/
192 CheckErrorFile(); /** verify that we can open an error log **/
195 if (debugLevel >= 10)
199 if (debugLevel == 0 && daemonMode)
201 if ( (oldpid = StorePid ()) != 0 )
203 if (oldpid == (long) -1)
205 ReadCatalog(MC_LOG_SET,MC_LOG_NO_CREATE,MC_DEF_LOG_NO_CREATE),
208 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_LOCK,MC_DEF_LOG_NO_LOCK),
214 * Check if we are restarting too fast...
221 * Initialize error file, open XDMCP socket, and set up interrupt handlers.
226 CreateWellKnownSockets ();
227 parent_pid = getpid(); /* PID of parent dtlogin process */
228 (void) signal (SIGTERM, StopAll);
229 (void) signal (SIGINT, StopAll);
232 * Set pseudo-user to "nobody". Xserver will be run as that pseudo-user
233 * rather than root (unless pseudo user is specifically set to another
234 * user via the Xservers file).
237 if ( (p = getpwnam ("nobody")) != NULL) {
241 * This should not happen, the "nobody" user should always be present.
242 * If it does, fall back to traditional values of the "root" user
251 * Ensure the interrupt handlers are set. The Passwd Etc. libraries
252 * (getpwnam()) disable SIGTERM and SIGINT.
255 (void) signal (SIGTERM, StopAll);
256 (void) signal (SIGINT, StopAll);
262 * Step 2 - Read /etc/Xservers and set up
265 * Keep a sub-daemon running
268 SetAccessFileTime ();
269 ScanAccessDatabase ();
270 #if !defined (ENABLE_DYNAMIC_LANGLIST)
272 #endif /* ENABLE_DYNAMIC_LANGLIST */
275 (void) signal (SIGHUP, RescanNotify);
276 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__linux__)
277 (void) signal (SIGCHLD, ChildNotify);
279 while (AnyWellKnownSockets() || AnyDisplaysLeft ())
289 #if defined(SYSV) && !defined(hpux) && !defined(_AIX) && !defined(__linux__)
297 Debug ("Nothing left to do, exiting\n");
301 RescanNotify( int arg )
303 Debug ("Caught SIGHUP\n");
305 #if defined(SYSV) || defined(SVR4)
306 signal (SIGHUP, RescanNotify);
317 static DisplayType acceptableTypes[] =
318 { { Local, Permanent, FromFile },
319 { Foreign, Permanent, FromFile },
322 #define NumTypes (sizeof (acceptableTypes) / sizeof (acceptableTypes[0]))
324 if (servers[0] == '/')
326 serversFile = fopen (servers, "r");
327 if (serversFile == NULL)
330 ReadCatalog(MC_LOG_SET,MC_LOG_NO_SRVACC,MC_DEF_LOG_NO_SRVACC),
334 if (ServersModTime == 0)
336 fstat (fileno (serversFile), &statb);
337 ServersModTime = statb.st_mtime;
339 while (fgets (lineBuf, sizeof (lineBuf)-1, serversFile))
341 len = strlen (lineBuf);
342 if (lineBuf[len-1] == '\n')
343 lineBuf[len-1] = '\0';
344 ParseDisplay (lineBuf, acceptableTypes, NumTypes, &puser);
346 fclose (serversFile);
350 ParseDisplay (servers, acceptableTypes, NumTypes, &puser);
356 MarkDisplay( struct display *d )
358 d->state = MissingEntry;
362 KillDisplay( struct display *d )
365 Debug("Sending HUP to display %s\n", d->name);
367 Debug("Sending HUP to display ?\n");
369 kill(d->pid, SIGHUP);
373 RescanServers( void )
375 Debug ("Rescanning servers\n");
377 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_REBUILD,MC_DEF_LOG_REBUILD),
379 #if !defined (ENABLE_DYNAMIC_LANGLIST)
381 #endif /* ENABLE_DYNAMIC_LANGLIST */
383 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_RESCAN,MC_DEF_LOG_RESCAN));
384 ForEachDisplay (MarkDisplay);
385 ForEachDisplay (KillDisplay);
389 SetAccessFileTime ();
390 ScanAccessDatabase ();
395 SetConfigFileTime( void )
399 if (stat (config, &statb) != -1)
400 ConfigModTime = statb.st_mtime;
405 SetAccessFileTime( void )
409 if (stat (accessFile, &statb) != -1)
410 AccessFileModTime = statb.st_mtime;
419 if (stat (config, &statb) != -1)
421 if (statb.st_mtime != ConfigModTime)
423 Debug ("Config file %s has changed, rereading\n", config);
425 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADCFG,MC_DEF_LOG_REREADCFG),
427 ConfigModTime = statb.st_mtime;
432 if (servers[0] == '/' && stat(servers, &statb) != -1)
434 if (statb.st_mtime != ServersModTime)
436 Debug ("Servers file %s has changed, rescanning\n", servers);
438 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADSRV,MC_DEF_LOG_REREADSRV),
440 ServersModTime = statb.st_mtime;
441 ForEachDisplay (MarkDisplay);
446 if (accessFile && accessFile[0] && stat (accessFile, &statb) != -1)
448 if (statb.st_mtime != AccessFileModTime)
450 Debug ("Access file %s has changed, rereading\n", accessFile);
452 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADACC,MC_DEF_LOG_REREADACC),
454 AccessFileModTime = statb.st_mtime;
455 ScanAccessDatabase ();
462 * catch a SIGTERM, kill all displays and exit
465 static int dt_shutdown = 0;
470 if (parent_pid != getpid())
473 * we got caught in a race condition - we are really a
474 * child dtlogin process that has been killed by the parent
475 * dtlogin process before we got a chance to return from
476 * fork() and remove this signal handler
478 Debug ("Child dtlogin caught signal %d before it could become a real child\n", arg);
479 (void) signal (arg, SIG_DFL); /* ensure no more handler */
480 TerminateProcess (getpid(), arg); /* and send signal again */
484 Debug ("Shutting down entire manager\n");
485 DestroyWellKnownSockets ();
488 ForEachDisplay (StopDisplay);
489 #if defined(SYSV) || defined(SVR4)
490 /* to avoid another one from killing us unceremoniously */
491 (void) signal (SIGTERM, StopAll);
492 (void) signal (SIGINT, StopAll);
497 * notice that a child has died and may need another
503 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__linux__) || defined(CSRG_BASED)
505 ChildNotify( int arg )
513 In HP-UX, SIGCHLDs are queued rather than lost if we are in the middle
514 of processing one (see SIGNAL(5), WARNINGS). The following code relies
517 If we have a socket, then we are using "select" to block
518 (WaitForSomething) rather than "wait". If a child dies, ChildReady is
519 set and the select unblocks. We then loop, processing the child that
520 died plus any that die while we are processing others. Finally we
521 activate the signal handler again and go around one more time in case a
522 child died right before activating the signal handler.
532 #if defined(SYSV) || defined(SVR4) || defined(hpux)
534 if (AnyWellKnownSockets()) {
535 while ( ChildReady ) {
537 while ((pid = waitpid((pid_t) -1, &status, WNOHANG)) > 0 )
539 while ((pid = wait3 (&status, WNOHANG, NULL)) > 0 )
541 ProcessChildDeath(pid, status);
544 (void) signal (SIGCHLD, ChildNotify);
549 /* XXX classic sysV signal race condition here with RescanNotify */
550 if ((pid = wait (&status)) != -1)
551 ProcessChildDeath(pid, status);
555 mask = sigblock (sigmask (SIGCHLD) | sigmask (SIGHUP));
556 Debug ("Signals blocked, mask was 0x%x\n", mask);
557 if (!ChildReady && !Rescan)
562 while ((pid = wait3 (&status, WNOHANG, (struct rusage *) 0)) > 0)
563 ProcessChildDeath(pid, status);
571 ProcessChildDeath( int pid, waitType status )
576 Debug ("Processing child death, pid = %d\n", pid);
580 if ( (d = FindDisplayByPid (pid)) != 0 ) {
584 * do process accounting...
587 #if !defined(CSRG_BASED)
588 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
593 * make sure authorization file is deleted...
597 if (d->authorization && d->authFile) {
598 (void) unlink (d->authFile);
606 * reset "startTries" ...
608 * Local displays: Only for clean exits of the server
609 * Foreign displays: Always except for OPENFAILED_DISPLAY
611 * Note: if startTries expires and a "getty" is run on the local
612 * display, startTries will be reset to zero before
613 * attempting to restart the server.
616 switch (waitVal (status)) {
617 case OBEYSESS_DISPLAY:
618 case RESERVER_DISPLAY:
622 case OPENFAILED_DISPLAY:
626 if (d->displayType.location != Local )
635 * process exit status...
638 switch (waitVal (status)) {
639 case UNMANAGE_DISPLAY:
640 Debug ("Display exited with UNMANAGE_DISPLAY\n");
644 case OBEYSESS_DISPLAY:
645 Debug ("Display exited with (check)OBEYSESS_DISPLAY\n");
646 if (d->displayType.lifetime != Permanent || d->status == zombie)
649 RestartDisplay (d, FALSE);
653 Debug ("Display exited with unknown status %d\n", waitVal(status));
654 LogError ((unsigned char *)"Unknown session exit code %d from process %d\n",
655 waitVal (status), pid);
659 case OPENFAILED_DISPLAY:
660 Debug ("Display exited with OPENFAILED_DISPLAY\n");
661 if (d->displayType.origin == FromXDMCP)
662 SendFailed (d, "Cannot open display");
664 if (d->displayType.location != Local)
667 if (d->displayType.origin == FromXDMCP ||
668 d->status == zombie ||
669 d->startTries >= d->startAttempts)
672 RestartDisplay (d, TRUE);
676 case RESERVER_DISPLAY:
677 Debug ("Display exited with RESERVER_DISPLAY\n");
678 if (d->displayType.origin == FromXDMCP || d->status == zombie)
681 RestartDisplay (d, TRUE);
684 case waitCompose (SIGTERM,0,0):
685 Debug ("Display exited on SIGTERM\n");
686 if (d->displayType.origin == FromXDMCP || d->status == zombie)
689 RestartDisplay (d, TRUE);
692 case REMANAGE_DISPLAY:
693 Debug ("Display exited with REMANAGE_DISPLAY\n");
695 * XDMCP will restart the session if the display
698 if (d->displayType.origin == FromXDMCP || d->status == zombie)
701 RestartDisplay (d, FALSE);
704 case SUSPEND_DISPLAY:
705 Debug ("Display exited with SUSPEND_DISPLAY\n");
706 if (d->displayType.location == Local)
709 RestartDisplay (d, FALSE);
714 else if ( (d = FindDisplayByServerPid (pid)) != 0 )
719 * do process accounting...
722 #if !defined(CSRG_BASED)
723 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
729 Debug ("Zombie server reaped, removing display %s\n", d->name);
733 Debug ("Phoenix server arises, restarting display %s\n", d->name);
734 d->status = notRunning;
737 Debug ("Server for display %s terminated unexpectedly, status %d\n", d->name, waitVal (status));
738 LogError ((unsigned char *)"Server for display %s terminated unexpectedly %d\n",
739 d->name, waitVal(status) );
742 Debug ("Terminating session pid %d\n", d->pid);
743 TerminateProcess (d->pid, SIGTERM);
747 Debug ("Server exited for notRunning session on display %s\n", d->name);
750 Debug ("Server for display %s is suspended\n", d->name);
752 d->status = notRunning;
758 Debug ("Unknown child termination, status %d\n", waitVal (status));
763 CheckDisplayStatus( struct display *d )
766 if (d->displayType.origin == FromFile)
777 Debug("Check %s: status=%d wakeupTime=%d\n", d->name,
778 d->status, wakeupTime);
779 if (d->status == suspended && wakeupTime >= 0)
780 if ( GettyRunning(d) || (d->gettyLine && (strcmp(d->gettyLine,"??") == 0)) )
781 if ( wakeupTime == 0 ) {
782 Debug("Polling of suspended server %s started.\n",
785 wakeupTime = (wakeupInterval < 10
787 : 2 * wakeupInterval );
790 Debug("Polling of suspended server %s stopped.\n",
792 wakeupTime = -1; /* disable polling */
793 d->status = notRunning; /* restart server */
795 if ( !dt_shutdown ) GettyMessage(d,2);
798 Debug("Polling of suspended server %s continued.\n",
800 wakeupTime = wakeupInterval; /* continue polling*/
803 if (d->status == notRunning)
811 StartDisplays( void )
813 ForEachDisplay (CheckDisplayStatus);
823 char start_fbconsole[1024];
826 Debug ("StartDisplay(): %s\n", d->name);
828 bzero(&status, sizeof(waitType));
829 if (d->authFile == NULL)
830 authFile_str = "NULL";
832 authFile_str = d->authFile;
834 Debug("(Old StartDisplay) d->authfile %s; authDir %s\n",
835 authFile_str, authDir);
838 * The following call to RemoveDisplay is to catch race conditions during
839 * shutdown. There is no point in starting a display if Dtlogin is in the
840 * process of shutting down...
842 if (d->displayType.origin == FromFile && dt_shutdown ) {
848 /* make a backup of the authFile before loading resources and */
849 /* copy it back to authFile field od display structure for X server */
850 /* to reread the host database list on reset */
856 snprintf(bkup, sizeof(bkup), "%s", d->authFile);
858 LoadDisplayResources (d);
860 /* The Xserver may NOT have been killed, so reuse the authFile. */
861 if (NULL == d->authFile &&
863 0 == strncmp(authDir, bkup, strlen(authDir)))
864 d->authFile= (char *) strdup(bkup);
866 if (d->authFile == NULL)
867 authFile_str = "NULL";
869 authFile_str = d->authFile;
871 Debug("(Mid StartDisplay) d->authfile %s; authDir %s; bkup %s\n",
872 authFile_str, authDir, bkup);
875 if (d->displayType.location == Local)
877 /* don't bother pinging local displays; we'll
878 * certainly notice when they exit
883 Debug ("SetLocalAuthorization %s, auth %s\n",
884 d->name, d->authNames);
886 SetLocalAuthorization (d);
889 * reset the server after writing the authorization information
890 * to make it read the file (for compatibility with old
891 * servers which read auth file only on reset instead of
892 * at first connection)
894 if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
895 kill (d->serverPid, d->resetSignal);
899 * initialize d->utmpId. Check to see if anyone else is using
900 * the requested ID. Always allow the first request for "dt" to
901 * succeed as utmp may have become corrupted.
904 if (d->utmpId == NULL) {
905 static int firsttime = 1;
906 static char letters[] = "0123456789abcdefghijklmnopqrstuvwxyzz";
909 d->utmpId = malloc(5);
910 strcpy(d->utmpId, UTMPREC_PREFIX);
916 if ( firsttime || UtmpIdOpen(d->utmpId)) {
921 strncpy(&(d->utmpId[strlen(d->utmpId)]), t++, 1);
923 } while (*t != '\0');
926 Debug ("All DT utmp IDs already in use. Removing display %s\n",
928 LogError ((unsigned char *)"All DT utmp IDs already in use. Removing display %s\n",
936 * set d->gettyLine to "console" for display ":0" if it is not
940 if (! d->gettyLine || strlen(d->gettyLine) == 0 ) {
943 if ( (p = index(d->name,':')) != NULL &&
944 ( strncmp(++p,"0",1) == 0 )) {
946 d->gettyLine = (char *) malloc(8);
947 strcpy(d->gettyLine, "console");
950 d->gettyLine = (char *) malloc(3);
951 strcpy(d->gettyLine, "??");
957 * if gettyLine is set to "console", set gettySpeed to "console" also
960 if (d->gettyLine && (strcmp(d->gettyLine, "console") == 0 ) ) {
962 free((char *) d->gettySpeed);
964 d->gettySpeed = (char *) malloc(8);
966 strcpy(d->gettySpeed, "console");
971 * start server. If it cannot be started and this is the console,
975 Debug("Attempting to start server for %s. startTries = %d\n",
976 d->name, d->startTries);
978 if (d->serverPid == -1) {
979 static int bootup = 0;
981 while (bootup++ < 5) {
982 if (GettyRunning(d)) {
993 if (d->serverPid == -1 &&
994 (d->startTries++ >= d->startAttempts ||
997 LogError ((unsigned char *)"Server for display %s can't be started.\n", d->name);
1010 /* this will only happen when using XDMCP */
1011 if (d->authorizations)
1012 SaveServerAuthorizations (d, d->authorizations, d->authNum);
1015 * Generate a utmp ID address for a foreign display. Use the last
1016 * four characters of the DISPLAY name, shifting left if they
1017 * are already in use...
1020 #if !defined(CSRG_BASED)
1021 if (d->utmpId == NULL) {
1026 d->utmpId = malloc(sizeof(u->ut_id) +1);
1028 i = strlen (d->name);
1029 if (i >= sizeof (u->ut_id))
1030 i -= sizeof (u->ut_id);
1034 for ( p = d->name, q = d->name + i; p <= q; q-- ) {
1035 (void) strncpy (d->utmpId, q, sizeof (u->ut_id));
1036 d->utmpId[sizeof(u->ut_id)] = '\0';
1037 if (UtmpIdOpen(d->utmpId))
1041 #ifdef DEF_NETWORK_DEV
1043 * If "networkDev" does not start with "/dev/" then foreign
1044 * accounting is turned off. Return utmpId to NULL.
1046 if (networkDev && strncmp(networkDev,"/dev/",5) !=0 ) {
1055 if (NULL == d->authFile)
1056 authFile_str = "NULL";
1058 authFile_str = d->authFile;
1060 Debug("(New StartDisplay) d->authfile %s; authDir %s\n",
1061 authFile_str, authDir);
1064 * make sure stderr is pointing to the current error log file...
1070 if (!nofork_session)
1076 switch (pid = fork ())
1081 if (!nofork_session) {
1083 signal (SIGPIPE, SIG_IGN);
1087 signal (SIGPIPE, SIG_IGN);
1091 * set global display name for Debug()
1099 strncpy(p, d->name, sizeof(DisplayName) - 1);
1100 DisplayName[sizeof(DisplayName)-1] = '\0';
1102 if ( (s = strchr(p,':')) != NULL )
1103 if ( (t = strchr(p,'.')) != NULL )
1108 SetAuthorization (d);
1111 * do process accounting...
1115 char *line = (d->displayType.location==Local)
1116 ? d->gettyLine : d->name;
1117 #ifdef DEF_NETWORK_DEV
1118 if (d->displayType.location != Local &&
1119 networkDev && !strncmp(networkDev,"/dev/",5))
1123 struct stat devinfo;
1124 devname = networkDev; /* networkDev resource */
1126 devexists = (lstat(devname,&devinfo)==0);
1128 if (!devexists && (MK_NETWORK_DEV(devname) < 0)) {
1129 Debug("Creation of file '%s' failed:\n %s (%d)\n",
1130 devname,strerror(errno),errno);
1133 for (line=devname; *line; line++);
1134 while (line>devname && *line!='/') line--;
1135 if (*line=='/') line++;
1137 Debug("Using pseudo-tty %s; line=%s\n",
1142 #if !defined(CSRG_BASED)
1143 Account(d, "LOGIN", line, getpid(), LOGIN_PROCESS, status);
1147 if (!WaitForServer (d))
1148 exit (OPENFAILED_DISPLAY);
1151 * start the fallback console, if the display is local..
1153 * if the display is remote, fbconsole should be started on
1157 if (d->displayType.location==Local) {
1158 if (d->authFile && strlen(d->authFile) > 0 ) {
1159 strcpy(buff, "XAUTHORITY=");
1160 strcat(buff, d->authFile);
1163 sprintf(start_fbconsole,"%s -d %s &",FBCONSOLE, d->name);
1165 if(system(start_fbconsole) == -1)
1166 Debug("Failed to start the fallback console - %s\n",FBCONSOLE);
1174 exit (REMANAGE_DISPLAY);
1178 Debug ("Child manager process started for %s. pid = %d\n",
1181 d->status = running;
1188 TerminateProcess(int pid, int sig )
1192 kill (pid, SIGCONT);
1197 * transition from running to zombie, suspended, or deleted
1201 StopDisplay( struct display *d )
1205 bzero(&status, sizeof(waitType));
1206 Debug("StopDisplay(): %s, server pid = %d, manager pid = %d, dt_shutdown = %d\n",
1207 d->name, d->serverPid, d->pid, dt_shutdown);
1209 if (d->serverPid != -1)
1210 /* don't remove the console */
1211 if ((d->displayType.location == Local) && !dt_shutdown )
1212 d->status = suspended;
1214 d->status = zombie; /* be careful about race conditions */
1217 TerminateProcess (d->pid, SIGTERM);
1219 if (d->serverPid != -1) {
1220 TerminateProcess (d->serverPid, d->termSignal);
1224 int translate=TR_ASCII;
1226 Debug ("Resetting keyboard\n");
1228 if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) {
1229 Debug("/dev/kbd open failed\n");
1230 } else if (ioctl(kbd_fd, KIOCTRANS, (caddr_t) &translate)) {
1231 Debug("Could not set /dev/kbd back to ASCII mode\n");
1237 if ((d->displayType.location == Local) || !dt_shutdown ) {
1238 /* don't remove the console */
1239 #if !defined(CSRG_BASED)
1240 Account(d, NULL, NULL, 0, DEAD_PROCESS, status);
1248 * transition from running to phoenix or notRunning
1252 RestartDisplay( struct display *d, int forceReserver )
1254 if (d->serverPid != -1 && (forceReserver || d->terminateServer))
1256 TerminateProcess (d->serverPid, d->termSignal);
1257 d->status = phoenix;
1261 d->status = notRunning;
1265 static FD_TYPE CloseMask;
1269 RegisterCloseOnFork( int fd )
1271 FD_SET (fd, &CloseMask);
1276 #if 0 /* utility routine: activate if needed... */
1280 FD_CLR (fd, &CloseMask);
1283 if (FD_ISSET (fd, &CloseMask))
1295 for (fd = 0; fd <= max; fd++)
1296 if (FD_ISSET (fd, &CloseMask))
1298 FD_ZERO (&CloseMask);
1305 static FILE *pidFilePtr;
1312 if (pidFile && pidFile[0] != '\0') {
1313 pidFd = open (pidFile, 2);
1314 if (pidFd == -1 && errno == ENOENT)
1317 * A Legacy OS wouldn't allow an fdopen
1318 * of a file descriptor handed back by creat(2).
1319 * The workaround is to close the created file, and
1320 * open it Read/Write. This will be transparent to HP-UX.
1321 * This code needs to be cleaned up - 05/22/18 - C
1323 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);
1387 SetTitle( char *name, char *ptr )
1395 * remove domain qualifiers and screens from name...
1398 if ( (p = malloc(strlen(name) + 1)) == NULL) return 0;
1401 if ( (s = strchr(p,':')) == NULL ) {
1406 if ( (t = strchr(s,'.')) != NULL )
1409 if ( (t = strchr(p,'.')) != NULL )
1413 * if there is enough room shift program name to left,
1414 * then append display name in remaining space.
1420 t = strrchr(s, '/');
1421 if ( (t != NULL) && ((t-s+1) >= (strlen(p) + 3)) ) {
1424 strcpy(s,t); /* "program" */
1425 strcat(s," <"); /* "program <" */
1426 strcat(s,p); /* "program <displayName" */
1427 strcat(s,">"); /* "program <displayName>" */
1430 length = length - strlen(s);
1443 /*****************************************************************************
1446 * Start a "getty" running on the console...
1448 *****************************************************************************/
1450 #if defined (_AIX) && defined (_POWER)
1451 #define GETTYPATH "/usr/sbin/getty"
1452 #elif defined(__OpenBSD__)
1453 #define GETTYPATH "/usr/libexec/getty"
1454 #elif defined(__linux__)
1455 #define GETTYPATH "/sbin/getty"
1457 #define GETTYPATH "/etc/getty"
1461 StartGetty( struct display *d )
1467 Debug ("StartGetty(): %s\n", d->name);
1469 bzero(&status, sizeof(waitType));
1471 * ensure that server is known dead...
1476 #if !defined(GETTYPATH)
1481 * check to see if we have a valid device (at least a non-null name)...
1484 if ( d->gettyLine &&
1485 (strlen(d->gettyLine) > 0) &&
1486 (strcmp(d->gettyLine,"??") != 0) )
1493 * if there is already a getty running on the device, set up
1494 * to start watching it. When it exits, restart the server...
1497 if ( GettyRunning(d) ) {
1498 d->status = suspended; /* set up to restart server */
1499 wakeupTime = 0; /* enable polling */
1501 sleep(1); /* wait for fbconsole to go away */
1502 GettyMessage(d,1); /* print a help message */
1509 * there is no getty running on the device, try to start one...
1512 d->status = phoenix; /* set up to restart server */
1515 switch (pid = fork ()) {
1520 * do process accounting...
1522 #if !defined(CSRG_BASED)
1523 Account(d, "LOGIN", NULL, getpid(), LOGIN_PROCESS, status);
1528 /* The tty argument for getty on AIX must be of the form "/dev/any tty"
1529 and so the following logic
1530 Raghu krovvidi 07.07.93
1532 strcpy(tynm,"/dev/");
1533 strcat(tynm,d->gettyLine);
1535 strcpy(tynm, d->gettyLine);
1538 Debug(" execing getty on %s\n",tynm);
1539 execl(GETTYPATH, "getty", tynm, d->gettySpeed, (char *)0);
1540 LogError ((unsigned char *)"Can not execute %s for %s: errno = %d\n",
1541 GETTYPATH, d->name, errno);
1543 exit (UNMANAGE_DISPLAY);
1546 Debug ("Fork of /etc/getty failed %s\n", d->name);
1547 LogError ((unsigned char *)"Can not fork to execute /etc/getty %s\n", d->name);
1554 Debug ("/etc/getty started on %s\n", d->name);
1557 #endif /* GETTYPATH not defined */
1561 /***************************************************************************
1565 * Print a message on the display device when going into No Windows mode.
1567 ***************************************************************************/
1570 GettyMessage( struct display *d, int msgnum )
1577 snprintf(buf, sizeof(buf), "/dev/%s", d->gettyLine);
1579 if ( (tf = fopen (buf, "a")) != NULL) {
1581 "\r\n\r\n*****************************************************************************\r\n*\r\n");
1586 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_SUS1_LABEL,MC_DEF_SUS1_LABEL));
1588 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_SUS2_LABEL,MC_DEF_SUS2_LABEL));
1590 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_SUS3_LABEL,MC_DEF_SUS3_LABEL));
1596 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_RES_LABEL,MC_DEF_RES_LABEL));
1603 (char *)ReadCatalog(MC_LABEL_SET,MC_START_LBLDPY,MC_DEF_START_LBLDPY),
1606 fprintf(tf, "%s", (char *)ReadCatalog(MC_LABEL_SET,MC_WAIT_LABEL,MC_DEF_WAIT_LABEL));
1612 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_X_LABEL,MC_DEF_X_LABEL),
1620 "*****************************************************************************\r\n");
1628 /***************************************************************************
1632 * See if a getty process is running against the display device. This
1633 * routine may need to be rewritten on other platforms if a different
1634 * mechanism is needed to make the determination.
1636 * Output: TRUE == a login process is active on the requested device
1637 * FALSE == a login process is not active on the device.
1639 * Sets d->gettyState:
1640 * NONE - no getty running or don't care
1641 * LOGIN - getty running
1642 * USER - user logged in on getty
1644 * Note: The check for a getty process running is made by scanning
1645 * /etc/utmp, looking for a login process on the respective device.
1646 * However, the child Dtlogin spawned by the master Dtlogin to
1647 * handle this display also is a "login process" according to
1648 * /etc/utmp. It provides a login path and therefore must register
1649 * itself as so. If a getty is also running, there are actually two
1650 * login processes running against the same device at the same time.
1652 * The child Dtlogin dies before the scan of /etc/utmp is made.
1653 * Provided /etc/utmp is updated correctly, the Dtlogin entry will
1654 * be marked as dead and will not show up in the scan of /etc/utmp.
1655 ***************************************************************************/
1658 GettyRunning( struct display *d )
1660 #if defined(__FreeBSD__) && OSMAJORVERSION > 8
1661 struct utmpx utmp; /* local struct for new entry */
1662 struct utmpx *u; /* pointer to entry in utmp file */
1664 struct utmp utmp; /* local struct for new entry */
1665 struct utmp *u; /* pointer to entry in utmp file */
1668 int rvalue; /* return value (TRUE or FALSE) */
1671 d->gettyState = DM_GETTY_NONE;
1674 * check to see if we have a valid device (at least a non-null name)...
1677 if ( d->gettyLine &&
1678 (strlen(d->gettyLine) > 0) &&
1679 (strcmp(d->gettyLine,"??") != 0) )
1685 #if defined(__FreeBSD__) && OSMAJORVERSION > 8
1686 bzero(&utmp, sizeof(struct utmpx));
1688 bzero(&utmp, sizeof(struct utmp));
1692 if (!strcmp(d->gettyLine,"console")) {
1696 fd = open("/dev/console",O_RDONLY);
1697 ttynm = ttyname(fd);
1699 strcpy(utmp.ut_line,ttynm);
1704 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line) - 1);
1705 utmp.ut_line[sizeof(utmp.ut_line) - 1] = 0;
1709 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line) - 1);
1710 utmp.ut_line[sizeof(utmp.ut_line) - 1] = 0;
1713 Debug("Checking for a getty on line %s.\n", utmp.ut_line);
1715 #if !defined(CSRG_BASED)
1720 while ( (u = getutent()) != NULL ) {
1722 if ((strncmp(u->ut_line, utmp.ut_line, sizeof(u->ut_line)) != 0) ||
1723 (strncmp(u->ut_id, d->utmpId, sizeof(u->ut_id)) == 0) )
1726 switch (u->ut_type) {
1728 case INIT_PROCESS: strcpy(buf, "INIT_PROCESS"); break;
1729 case LOGIN_PROCESS: strcpy(buf, "LOGIN_PROCESS"); break;
1730 case USER_PROCESS: strcpy(buf, "USER_PROCESS"); break;
1731 case DEAD_PROCESS: strcpy(buf, "DEAD_PROCESS"); break;
1732 default: strcpy(buf, "UNKNOWN"); break;
1735 Debug("Utmp info: id=%.4s, user=%s, line=%s, pid=%d, type=%s\n",
1736 u->ut_id, u->ut_user, u->ut_line, u->ut_pid, buf);
1738 if ( u->ut_type == INIT_PROCESS || u->ut_type == LOGIN_PROCESS) {
1739 d->gettyState = DM_GETTY_LOGIN;
1741 else if (wakeupTime <= 0 && u->ut_type == USER_PROCESS) {
1742 d->gettyState = DM_GETTY_USER;
1745 if (d->gettyState != DM_GETTY_NONE)
1753 #endif /* !CSRG_BASED */
1759 /***************************************************************************
1763 * Check if enough time has elapsed since shutdown.
1765 * This is primarily to work with /etc/shutdown. When shutdown kills
1766 * dtlogin (/etc/killall), init immediately restarts it. Shutdown kills
1767 * it again and init restarts it. At each restart, the X-server may start
1768 * on the local display and then subsequently be killed. The user sees a
1769 * flashing screen and sometimes the console is left in an unreset state.
1771 * When Dtlogin shuts down, it touches the access time on the Xservers
1772 * file. (MarkShutdownTime()). This time is then used to determine if
1773 * sufficient time has elapsed before restarting.
1775 ***************************************************************************/
1778 CheckRestartTime( void )
1783 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1785 Debug("Checking restart time.\n");
1788 /* only those other systems are this slow :-) */
1789 sleeptime = 6 - (int) (time((time_t *) 0) - statb.st_atime);
1791 sleeptime = 30 - (int) (time((time_t *) 0) - statb.st_atime);
1794 if ( sleeptime > 30 ) sleeptime = 30;
1796 if ( sleeptime > 0 ) {
1797 Debug("Restarting too soon after shutdown. Sleeping %d seconds.\n",
1806 /***************************************************************************
1810 * Save the time when we shut down to check later for too fast of a restart.
1812 ***************************************************************************/
1815 MarkShutdownTime( void )
1818 struct utimbuf timebuf;
1820 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1822 Debug("Marking shutdown time.\n");
1824 timebuf.actime = time((time_t *) 0 );
1825 timebuf.modtime = statb.st_mtime;
1827 if ( (utime(servers, &timebuf)) != 0 ) {
1828 Debug("MarkShutdownTime(): utime() error = %d\n", errno);
1834 /***************************************************************************
1838 * Make the default dt directory "/var/dt" if needed.
1840 ***************************************************************************/
1842 dtMakeDefaultDir( void )
1844 dtmkdir("/var", 0755, 0);
1845 dtmkdir("/var/dt", 0755, 1);
1846 dtmkdir("/var/dt/tmp", 0755, 1);
1847 dtmkdir("/var/dt/appconfig", 0755, 1);
1848 dtmkdir("/var/dt/appconfig/appmanager", 0755, 1);
1852 dtmkdir(char *dir, mode_t dir_mode, int force)
1854 struct stat file_status;
1856 if ( stat(dir, &file_status) != 0) {
1857 /** try to create it **/
1858 if ( mkdir(dir, dir_mode) == 0) {
1859 chmod(dir, dir_mode); /** since umask is non-zero **/
1860 Debug("Created dir %s\n", dir);
1862 LogError((unsigned char *)"Unable to create dir %s\n", dir);
1865 if ( force && (file_status.st_mode & dir_mode) != dir_mode) {
1866 /** try to set correct permissions **/
1867 if ( chmod(dir, file_status.st_mode | dir_mode) == 0) {
1868 Debug("Set permissions on %s\n", dir);
1870 LogError((unsigned char *)
1871 "Unable to set permissions on %s\n", dir);