1 /* (c) Copyright 1997 The Open Group */
3 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
4 * (c) Copyright 1993, 1994 International Business Machines Corp. *
5 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
6 * (c) Copyright 1993, 1994 Novell, Inc. *
9 * xdm - display manager daemon
11 * $TOG: dm.c /main/18 1999/01/19 17:44:08 mgreess $
13 * Copyright 1988 Massachusetts Institute of Technology
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted, provided
17 * that the above copyright notice appear in all copies and that both that
18 * copyright notice and this permission notice appear in supporting
19 * documentation, and that the name of M.I.T. not be used in advertising or
20 * publicity pertaining to distribution of the software without specific,
21 * written prior permission. M.I.T. makes no representations about the
22 * suitability of this software for any purpose. It is provided "as is"
23 * without express or implied warranty.
25 * Author: Keith Packard, MIT X Consortium
32 # include <sys/signal.h>
33 # include <sys/stat.h>
40 #if defined (SYSV) || defined (SVR4)
54 #define sigmask(m) (1 << (( m-1)))
58 /***************************************************************************
60 * External variable declarations
62 ***************************************************************************/
64 #if defined(USL) || defined(__uxp__)
65 extern int makepttypair ();
69 /***************************************************************************
71 * Local procedure declarations
73 ***************************************************************************/
75 static void CheckDisplayStatus( struct display *d) ;
76 static void CheckRestartTime( void ) ;
77 static void ChildNotify( int arg ) ;
78 static void MarkDisplay( struct display *d) ;
79 static void KillDisplay( struct display *d) ;
80 static void MarkShutdownTime( void ) ;
81 static void ProcessChildDeath( int pid, waitType status) ;
82 static void RescanIfMod( void ) ;
83 static void RescanNotify( int arg ) ;
84 static void RescanServers( void ) ;
85 static void RestartDisplay( struct display *d, int forceReserver) ;
86 static int ScanServers( void ) ;
87 static void SetAccessFileTime( void ) ;
88 static void SetConfigFileTime( void ) ;
89 static int StartGetty( struct display *d) ;
90 static void StopAll( int arg ) ;
91 static long StorePid( void ) ;
92 static void TerminateProcess( int pid, int sig) ;
93 static void UnlockPidFile( void ) ;
94 static void dtMakeDefaultDir( void );
95 static void dtmkdir(char *dir, mode_t dir_mode);
100 /***************************************************************************
104 ***************************************************************************/
105 struct passwd puser; /* pseudo-user password entry */
108 static long ServersModTime, ConfigModTime, AccessFileModTime;
112 char DisplayName[32]="main";
115 int nofork_session = 0;
119 char *Title; /* Global argv[0] */
123 static int parent_pid = -1; /* PID of parent dtlogin process */
126 /***************************************************************************/
129 main( int argc, char **argv )
133 struct passwd *p; /* pointer to passwd structure (pwd.h) */
136 * make sure at least world write access is disabled...
138 if ( (oldumask = umask(022) & 002) == 002)
139 (void) umask(oldumask);
143 TitleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - Title;
148 * save program name and path...
151 if ( (progName = malloc(strlen(argv[0]) + 1)) != NULL )
152 strcpy(progName, argv[0]);
154 #if defined(USL) || defined(__uxp__)
155 /* create master slave pair for use in login */
156 if (makepttypair () < 0)
158 Debug ("Could not create pty for use in login");
165 * Step 1 - load configuration parameters
167 InitResources (argc, argv);
168 SetConfigFileTime ();
171 * Only allow root to run xdm to avoid problems (HP 700/X version)
173 if (debugLevel == 0 && getuid() != 0)
176 (char *)ReadCatalog(MC_ERROR_SET,MC_BAD_ROOT,MC_DEF_BAD_ROOT),
181 dtMakeDefaultDir(); /** Create /var/dt if needed **/
182 CheckErrorFile(); /** verify that we can open an error log **/
185 if (debugLevel >= 10)
189 if (debugLevel == 0 && daemonMode)
191 if ( (oldpid = StorePid ()) != 0 )
193 if (oldpid == (long) -1)
195 ReadCatalog(MC_LOG_SET,MC_LOG_NO_CREATE,MC_DEF_LOG_NO_CREATE),
198 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_LOCK,MC_DEF_LOG_NO_LOCK),
204 * Check if we are restarting too fast...
211 * Initialize error file, open XDMCP socket, and set up interrupt handlers.
216 CreateWellKnownSockets ();
217 parent_pid = getpid(); /* PID of parent dtlogin process */
218 (void) signal (SIGTERM, StopAll);
219 (void) signal (SIGINT, StopAll);
222 * Set pseudo-user to "nobody". Xserver will be run as that pseudo-user
223 * rather than root (unless pseudo user is specifically set to another
224 * user via the Xservers file).
227 if ( (p = getpwnam ("nobody")) != NULL) {
231 * This should not happen, the "nobody" user should always be present.
232 * If it does, fall back to traditional values of the "root" user
241 * Ensure the interrupt handlers are set. The Passwd Etc. libraries
242 * (getpwnam()) disable SIGTERM and SIGINT.
245 (void) signal (SIGTERM, StopAll);
246 (void) signal (SIGINT, StopAll);
252 * Step 2 - Read /etc/Xservers and set up
255 * Keep a sub-daemon running
258 SetAccessFileTime ();
259 ScanAccessDatabase ();
260 #if !defined (ENABLE_DYNAMIC_LANGLIST)
262 #endif /* ENABLE_DYNAMIC_LANGLIST */
265 (void) signal (SIGHUP, RescanNotify);
266 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__uxp__)|| defined (__osf__) || defined(linux)
267 (void) signal (SIGCHLD, ChildNotify);
269 while (AnyWellKnownSockets() || AnyDisplaysLeft ())
279 #if defined(SYSV) && !defined(hpux) && !defined(_AIX) && !defined(__uxp__) && !defined (__osf__) && !defined(linux)
287 Debug ("Nothing left to do, exiting\n");
291 RescanNotify( int arg )
293 Debug ("Caught SIGHUP\n");
295 #if defined(SYSV) || defined(SVR4)
296 signal (SIGHUP, RescanNotify);
307 static DisplayType acceptableTypes[] =
308 { { Local, Permanent, FromFile },
309 { Foreign, Permanent, FromFile },
312 #define NumTypes (sizeof (acceptableTypes) / sizeof (acceptableTypes[0]))
314 if (servers[0] == '/')
316 serversFile = fopen (servers, "r");
317 if (serversFile == NULL)
320 ReadCatalog(MC_LOG_SET,MC_LOG_NO_SRVACC,MC_DEF_LOG_NO_SRVACC),
324 if (ServersModTime == 0)
326 fstat (fileno (serversFile), &statb);
327 ServersModTime = statb.st_mtime;
329 while (fgets (lineBuf, sizeof (lineBuf)-1, serversFile))
331 len = strlen (lineBuf);
332 if (lineBuf[len-1] == '\n')
333 lineBuf[len-1] = '\0';
334 ParseDisplay (lineBuf, acceptableTypes, NumTypes, &puser);
336 fclose (serversFile);
340 ParseDisplay (servers, acceptableTypes, NumTypes, &puser);
345 MarkDisplay( struct display *d )
347 d->state = MissingEntry;
351 KillDisplay( struct display *d )
354 Debug("Sending HUP to display %s\n", d->name);
356 Debug("Sending HUP to display ?\n");
358 kill(d->pid, SIGHUP);
362 RescanServers( void )
364 Debug ("Rescanning servers\n");
366 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_REBUILD,MC_DEF_LOG_REBUILD),
368 #if !defined (ENABLE_DYNAMIC_LANGLIST)
370 #endif /* ENABLE_DYNAMIC_LANGLIST */
372 LogInfo (ReadCatalog(MC_ERROR_SET,MC_LOG_RESCAN,MC_DEF_LOG_RESCAN));
373 ForEachDisplay (MarkDisplay);
374 ForEachDisplay (KillDisplay);
378 SetAccessFileTime ();
379 ScanAccessDatabase ();
384 SetConfigFileTime( void )
388 if (stat (config, &statb) != -1)
389 ConfigModTime = statb.st_mtime;
394 SetAccessFileTime( void )
398 if (stat (accessFile, &statb) != -1)
399 AccessFileModTime = statb.st_mtime;
408 if (stat (config, &statb) != -1)
410 if (statb.st_mtime != ConfigModTime)
412 Debug ("Config file %s has changed, rereading\n", config);
414 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADCFG,MC_DEF_LOG_REREADCFG),
416 ConfigModTime = statb.st_mtime;
421 if (servers[0] == '/' && stat(servers, &statb) != -1)
423 if (statb.st_mtime != ServersModTime)
425 Debug ("Servers file %s has changed, rescanning\n", servers);
427 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADSRV,MC_DEF_LOG_REREADSRV),
429 ServersModTime = statb.st_mtime;
430 ForEachDisplay (MarkDisplay);
435 if (accessFile && accessFile[0] && stat (accessFile, &statb) != -1)
437 if (statb.st_mtime != AccessFileModTime)
439 Debug ("Access file %s has changed, rereading\n", accessFile);
441 ReadCatalog(MC_ERROR_SET,MC_LOG_REREADACC,MC_DEF_LOG_REREADACC),
443 AccessFileModTime = statb.st_mtime;
444 ScanAccessDatabase ();
451 * catch a SIGTERM, kill all displays and exit
454 static int dt_shutdown = 0;
459 if (parent_pid != getpid())
462 * we got caught in a race condition - we are really a
463 * child dtlogin process that has been killed by the parent
464 * dtlogin process before we got a chance to return from
465 * fork() and remove this signal handler
467 Debug ("Child dtlogin caught signal %d before it could become a real child\n", arg);
468 (void) signal (arg, SIG_DFL); /* ensure no more handler */
469 TerminateProcess (getpid(), arg); /* and send signal again */
473 Debug ("Shutting down entire manager\n");
474 DestroyWellKnownSockets ();
477 ForEachDisplay (StopDisplay);
478 #if defined(SYSV) || defined(SVR4)
479 /* to avoid another one from killing us unceremoniously */
480 (void) signal (SIGTERM, StopAll);
481 (void) signal (SIGINT, StopAll);
486 * notice that a child has died and may need another
492 #if !defined(SYSV) || defined(hpux) || defined(_AIX) || defined(__uxp__) || defined (__osf__) || defined(linux)
494 ChildNotify( int arg )
502 In HP-UX, SIGCHLDs are queued rather than lost if we are in the middle
503 of processing one (see SIGNAL(5), WARNINGS). The following code relies
506 If we have a socket, then we are using "select" to block
507 (WaitForSomething) rather than "wait". If a child dies, ChildReady is
508 set and the select unblocks. We then loop, processing the child that
509 died plus any that die while we are processing others. Finally we
510 activate the signal handler again and go around one more time in case a
511 child died right before activating the signal handler.
521 #if defined(SYSV) || defined(SVR4) || defined(hpux)
523 if (AnyWellKnownSockets()) {
524 while ( ChildReady ) {
526 while ((pid = waitpid((pid_t) -1, &status, WNOHANG)) > 0 )
528 while ((pid = wait3 (&status, WNOHANG, NULL)) > 0 )
530 ProcessChildDeath(pid, status);
533 (void) signal (SIGCHLD, ChildNotify);
538 /* XXX classic sysV signal race condition here with RescanNotify */
539 if ((pid = wait (&status)) != -1)
540 ProcessChildDeath(pid, status);
544 mask = sigblock (sigmask (SIGCHLD) | sigmask (SIGHUP));
545 Debug ("Signals blocked, mask was 0x%x\n", mask);
546 if (!ChildReady && !Rescan)
551 while ((pid = wait3 (&status, WNOHANG, (struct rusage *) 0)) > 0)
552 ProcessChildDeath(pid, status);
560 ProcessChildDeath( int pid, waitType status )
565 Debug ("Processing child death, pid = %d\n", pid);
569 if ( (d = FindDisplayByPid (pid)) != 0 ) {
573 * do process accounting...
576 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
580 * make sure authorization file is deleted...
584 if (d->authorization && d->authFile) {
585 (void) unlink (d->authFile);
593 * reset "startTries" ...
595 * Local displays: Only for clean exits of the server
596 * Foreign displays: Always except for OPENFAILED_DISPLAY
598 * Note: if startTries expires and a "getty" is run on the local
599 * display, startTries will be reset to zero before
600 * attempting to restart the server.
603 switch (waitVal (status)) {
604 case OBEYSESS_DISPLAY:
605 case RESERVER_DISPLAY:
609 case OPENFAILED_DISPLAY:
613 if (d->displayType.location != Local )
622 * process exit status...
625 switch (waitVal (status)) {
626 case UNMANAGE_DISPLAY:
627 Debug ("Display exited with UNMANAGE_DISPLAY\n");
631 case OBEYSESS_DISPLAY:
632 Debug ("Display exited with (check)OBEYSESS_DISPLAY\n");
633 if (d->displayType.lifetime != Permanent || d->status == zombie)
636 RestartDisplay (d, FALSE);
640 Debug ("Display exited with unknown status %d\n", waitVal(status));
641 LogError ((unsigned char *)"Unknown session exit code %d from process %d\n",
642 waitVal (status), pid);
646 case OPENFAILED_DISPLAY:
647 Debug ("Display exited with OPENFAILED_DISPLAY\n");
648 if (d->displayType.origin == FromXDMCP)
649 SendFailed (d, "Cannot open display");
651 if (d->displayType.location != Local)
654 if (d->displayType.origin == FromXDMCP ||
655 d->status == zombie ||
656 d->startTries >= d->startAttempts)
659 RestartDisplay (d, TRUE);
663 case RESERVER_DISPLAY:
664 Debug ("Display exited with RESERVER_DISPLAY\n");
665 if (d->displayType.origin == FromXDMCP || d->status == zombie)
668 RestartDisplay (d, TRUE);
671 case waitCompose (SIGTERM,0,0):
672 Debug ("Display exited on SIGTERM\n");
673 if (d->displayType.origin == FromXDMCP || d->status == zombie)
676 RestartDisplay (d, TRUE);
679 case REMANAGE_DISPLAY:
680 Debug ("Display exited with REMANAGE_DISPLAY\n");
682 * XDMCP will restart the session if the display
685 if (d->displayType.origin == FromXDMCP || d->status == zombie)
688 RestartDisplay (d, FALSE);
691 case SUSPEND_DISPLAY:
692 Debug ("Display exited with SUSPEND_DISPLAY\n");
693 if (d->displayType.location == Local)
696 RestartDisplay (d, FALSE);
701 else if ( (d = FindDisplayByServerPid (pid)) != 0 )
706 * do process accounting...
709 Account(d, NULL, NULL, pid, DEAD_PROCESS, status);
714 Debug ("Zombie server reaped, removing display %s\n", d->name);
718 Debug ("Phoenix server arises, restarting display %s\n", d->name);
719 d->status = notRunning;
722 Debug ("Server for display %s terminated unexpectedly, status %d\n", d->name, waitVal (status));
723 LogError ((unsigned char *)"Server for display %s terminated unexpectedly %d\n",
724 d->name, waitVal(status) );
727 Debug ("Terminating session pid %d\n", d->pid);
728 TerminateProcess (d->pid, SIGTERM);
732 Debug ("Server exited for notRunning session on display %s\n", d->name);
735 Debug ("Server for display %s is suspended\n", d->name);
737 d->status = notRunning;
743 Debug ("Unknown child termination, status %d\n", waitVal (status));
748 CheckDisplayStatus( struct display *d )
751 if (d->displayType.origin == FromFile)
762 Debug("Check %s: status=%d wakeupTime=%d\n", d->name,
763 d->status, wakeupTime);
764 if (d->status == suspended && wakeupTime >= 0)
765 if ( GettyRunning(d) || (strcmp(d->gettyLine,"??") == 0))
766 if ( wakeupTime == 0 ) {
767 Debug("Polling of suspended server %s started.\n",
770 wakeupTime = (wakeupInterval < 10
772 : 2 * wakeupInterval );
775 Debug("Polling of suspended server %s stopped.\n",
777 wakeupTime = -1; /* disable polling */
778 d->status = notRunning; /* restart server */
780 if ( !dt_shutdown ) GettyMessage(d,2);
783 Debug("Polling of suspended server %s continued.\n",
785 wakeupTime = wakeupInterval; /* continue polling*/
788 if (d->status == notRunning)
796 StartDisplays( void )
798 ForEachDisplay (CheckDisplayStatus);
808 char start_fbconsole[1024];
811 Debug ("StartDisplay(): %s\n", d->name);
813 bzero(&status, sizeof(waitType));
814 if (d->authFile == NULL)
815 authFile_str = "NULL";
817 authFile_str = d->authFile;
819 Debug("(Old StartDisplay) d->authfile %s; authDir %s\n",
820 authFile_str, authDir);
823 * The following call to RemoveDisplay is to catch race conditions during
824 * shutdown. There is no point in starting a display if Dtlogin is in the
825 * process of shutting down...
827 if (d->displayType.origin == FromFile && dt_shutdown ) {
833 /* make a backup of the authFile before loading resources and */
834 /* copy it back to authFile field od display structure for X server */
835 /* to reread the host database list on reset */
841 strcpy(bkup ,d->authFile);
843 LoadDisplayResources (d);
845 /* The Xserver may NOT have been killed, so reuse the authFile. */
846 if (NULL == d->authFile &&
848 0 == strncmp(authDir, bkup, strlen(authDir)))
849 d->authFile= (char *) strdup(bkup);
851 if (d->authFile == NULL)
852 authFile_str = "NULL";
854 authFile_str = d->authFile;
856 Debug("(Mid StartDisplay) d->authfile %s; authDir %s; bkup %s\n",
857 authFile_str, authDir, bkup);
860 if (d->displayType.location == Local)
862 /* don't bother pinging local displays; we'll
863 * certainly notice when they exit
868 Debug ("SetLocalAuthorization %s, auth %s\n",
869 d->name, d->authNames);
871 SetLocalAuthorization (d);
874 * reset the server after writing the authorization information
875 * to make it read the file (for compatibility with old
876 * servers which read auth file only on reset instead of
877 * at first connection)
879 if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
880 kill (d->serverPid, d->resetSignal);
885 * initialize d->utmpId. Check to see if anyone else is using
886 * the requested ID. Always allow the first request for "dt" to
887 * succeed as utmp may have become corrupted.
890 if (d->utmpId == NULL) {
891 static int firsttime = 1;
892 static char letters[] = "0123456789abcdefghijklmnopqrstuvwxyzz";
895 d->utmpId = malloc(5);
896 strcpy(d->utmpId, UTMPREC_PREFIX);
902 if ( firsttime || UtmpIdOpen(d->utmpId)) {
907 strncpy(&(d->utmpId[strlen(d->utmpId)]), t++, 1);
909 } while (*t != NULL);
912 Debug ("All DT utmp IDs already in use. Removing display %s\n",
914 LogError ((unsigned char *)"All DT utmp IDs already in use. Removing display %s\n",
923 * set d->gettyLine to "console" for display ":0" if it is not
927 if (! d->gettyLine || strlen(d->gettyLine) == 0 ) {
930 if ( (p = index(d->name,':')) != NULL &&
931 ( strncmp(++p,"0",1) == 0 )) {
933 d->gettyLine = (char *) malloc(8);
934 strcpy(d->gettyLine, "console");
937 d->gettyLine = (char *) malloc(3);
938 strcpy(d->gettyLine, "??");
944 * if gettyLine is set to "console", set gettySpeed to "console" also
947 if (d->gettyLine && (strcmp(d->gettyLine, "console") == 0 ) ) {
949 free((char *) d->gettySpeed);
951 d->gettySpeed = (char *) malloc(8);
953 strcpy(d->gettySpeed, "console");
958 * start server. If it cannot be started and this is the console,
962 Debug("Attempting to start server for %s. startTries = %d\n",
963 d->name, d->startTries);
965 if (d->serverPid == -1) {
966 static int bootup = 0;
968 while (bootup++ < 5) {
969 if (GettyRunning(d)) {
980 if (d->serverPid == -1 &&
981 (d->startTries++ >= d->startAttempts ||
984 LogError ((unsigned char *)"Server for display %s can't be started.\n", d->name);
997 /* this will only happen when using XDMCP */
998 if (d->authorizations)
999 SaveServerAuthorizations (d, d->authorizations, d->authNum);
1002 * Generate a utmp ID address for a foreign display. Use the last
1003 * four characters of the DISPLAY name, shifting left if they
1004 * are already in use...
1007 if (d->utmpId == NULL) {
1012 d->utmpId = malloc(sizeof(u->ut_id) +1);
1014 i = strlen (d->name);
1015 if (i >= sizeof (u->ut_id))
1016 i -= sizeof (u->ut_id);
1020 for ( p = d->name, q = d->name + i; p <= q; q-- ) {
1021 (void) strncpy (d->utmpId, q, sizeof (u->ut_id));
1022 d->utmpId[sizeof(u->ut_id)] = '\0';
1023 if (UtmpIdOpen(d->utmpId))
1027 #ifdef DEF_NETWORK_DEV
1029 * If "networkDev" does not start with "/dev/" then foreign
1030 * accounting is turned off. Return utmpId to NULL.
1032 if (networkDev && strncmp(networkDev,"/dev/",5) !=0 ) {
1040 if (NULL == d->authFile)
1041 authFile_str = "NULL";
1043 authFile_str = d->authFile;
1045 Debug("(New StartDisplay) d->authfile %s; authDir %s\n",
1046 authFile_str, authDir);
1049 * make sure stderr is pointing to the current error log file...
1055 if (!nofork_session)
1061 switch (pid = fork ())
1066 if (!nofork_session) {
1068 signal (SIGPIPE, SIG_IGN);
1072 signal (SIGPIPE, SIG_IGN);
1076 * set global display name for Debug()
1084 strncpy(p, d->name, sizeof(DisplayName));
1085 DisplayName[sizeof(DisplayName)-1] = '\0';
1087 if ( (s = strchr(p,':')) != NULL )
1088 if ( (t = strchr(p,'.')) != NULL )
1093 SetAuthorization (d);
1096 * do process accounting...
1100 char *line = (d->displayType.location==Local)
1101 ? d->gettyLine : d->name;
1102 #ifdef DEF_NETWORK_DEV
1103 if (d->displayType.location != Local &&
1104 networkDev && !strncmp(networkDev,"/dev/",5))
1108 struct stat devinfo;
1109 devname = networkDev; /* networkDev resource */
1111 devexists = (lstat(devname,&devinfo)==0);
1113 if (!devexists && (MK_NETWORK_DEV(devname) < 0)) {
1114 Debug("Creation of file '%s' failed:\n %s (%d)\n",
1115 devname,strerror(errno),errno);
1118 for (line=devname; *line; line++);
1119 while (line>devname && *line!='/') line--;
1120 if (*line=='/') line++;
1122 Debug("Using pseudo-tty %s; line=%s\n",
1127 Account(d, "LOGIN", line, getpid(), LOGIN_PROCESS, status);
1130 if (!WaitForServer (d))
1131 exit (OPENFAILED_DISPLAY);
1134 * start the fallback console, if the display is local..
1136 * if the display is remote, fbconsole should be started on
1140 if (d->displayType.location==Local) {
1141 if (d->authFile && strlen(d->authFile) > 0 ) {
1142 strcpy(buff, "XAUTHORITY=");
1143 strcat(buff, d->authFile);
1146 sprintf(start_fbconsole,"%s -d %s &",FBCONSOLE, d->name);
1148 if(system(start_fbconsole) == -1)
1149 Debug("Failed to start the fallback console - %s\n",FBCONSOLE);
1157 exit (REMANAGE_DISPLAY);
1161 Debug ("Child manager process started for %s. pid = %d\n",
1164 d->status = running;
1170 TerminateProcess(int pid, int sig )
1174 kill (pid, SIGCONT);
1179 * transition from running to zombie, suspended, or deleted
1183 StopDisplay( struct display *d )
1187 bzero(&status, sizeof(waitType));
1188 Debug("StopDisplay(): %s, server pid = %d, manager pid = %d, dt_shutdown = %d\n",
1189 d->name, d->serverPid, d->pid, dt_shutdown);
1191 if (d->serverPid != -1)
1192 /* don't remove the console */
1193 if ((d->displayType.location == Local) && !dt_shutdown )
1194 d->status = suspended;
1196 d->status = zombie; /* be careful about race conditions */
1199 TerminateProcess (d->pid, SIGTERM);
1201 if (d->serverPid != -1) {
1202 TerminateProcess (d->serverPid, d->termSignal);
1206 int translate=TR_ASCII;
1208 Debug ("Resetting keyboard\n");
1210 if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) {
1211 Debug("/dev/kbd open failed\n");
1212 } else if (ioctl(kbd_fd, KIOCTRANS, (caddr_t) &translate)) {
1213 Debug("Could not set /dev/kbd back to ASCII mode\n");
1219 if ((d->displayType.location == Local) || !dt_shutdown ) {
1220 /* don't remove the console */
1221 Account(d, NULL, NULL, 0, DEAD_PROCESS, status);
1228 * transition from running to phoenix or notRunning
1232 RestartDisplay( struct display *d, int forceReserver )
1234 if (d->serverPid != -1 && (forceReserver || d->terminateServer))
1236 TerminateProcess (d->serverPid, d->termSignal);
1237 d->status = phoenix;
1241 d->status = notRunning;
1245 static FD_TYPE CloseMask;
1249 RegisterCloseOnFork( int fd )
1251 FD_SET (fd, &CloseMask);
1256 #if 0 /* utility routine: activate if needed... */
1260 FD_CLR (fd, &CloseMask);
1263 if (FD_ISSET (fd, &CloseMask))
1274 for (fd = 0; fd <= max; fd++)
1275 if (FD_ISSET (fd, &CloseMask))
1277 FD_ZERO (&CloseMask);
1282 static FILE *pidFilePtr;
1289 if (pidFile && pidFile[0] != '\0') {
1290 pidFd = open (pidFile, 2);
1291 if (pidFd == -1 && errno == ENOENT)
1294 * HP OSF/1 will not allow an fdopen
1295 * of a file descriptor handed back by creat(2).
1296 * The workaround is to close the created file, and
1297 * open it Read/Write. This will be transparent to HP-UX.
1299 pidFd = creat (pidFile, 0644);
1301 pidFd = open (pidFile, 2);
1303 if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+")))
1305 LogError ((unsigned char *)"Process ID file %s cannot be opened\n",
1309 if (fscanf (pidFilePtr, "%ld", &oldpid) != 1)
1311 fseek (pidFilePtr, 0l, 0);
1314 #if defined (SYSV) || defined (SVR4)
1315 if (lockf (pidFd, F_TLOCK, 0) == -1)
1317 if ((errno == EAGAIN) || (errno == EACCES))
1323 if (flock (pidFd, LOCK_EX|LOCK_NB) == -1)
1325 if (errno == EWOULDBLOCK)
1334 * HPUX releases the lock on ANY close of the file, not just the
1335 * one that established the lock. -prr
1337 /* close(creat(pidFile, 0644)); */
1339 (void) creat(pidFile, 0644);
1340 fprintf (pidFilePtr, "%ld\n", (long)getpid ());
1341 (void) fflush(pidFilePtr);
1342 RegisterCloseOnFork(pidFd);
1348 UnlockPidFile( void )
1351 #if defined (SYSV) || defined (SVR4)
1352 lockf (pidFd, F_ULOCK, 0);
1354 flock (pidFd, LOCK_UN);
1357 fclose (pidFilePtr);
1367 int left = TitleLen;
1374 while (s = va_arg (args, char *))
1376 while (*s && left > 0)
1393 SetTitle( char *name, char *ptr )
1401 * remove domain qualifiers and screens from name...
1404 if ( (p = malloc(strlen(name) + 1)) == NULL) return;
1407 if ( (s = strchr(p,':')) == NULL ) {
1412 if ( (t = strchr(s,'.')) != NULL )
1415 if ( (t = strchr(p,'.')) != NULL )
1419 * if there is enough room shift program name to left,
1420 * then append display name in remaining space.
1426 t = strrchr(s, '/');
1427 if ( (t != NULL) && ((t-s+1) >= (strlen(p) + 3)) ) {
1430 strcpy(s,t); /* "program" */
1431 strcat(s," <"); /* "program <" */
1432 strcat(s,p); /* "program <displayName" */
1433 strcat(s,">"); /* "program <displayName>" */
1436 length = length - strlen(s);
1448 /*****************************************************************************
1451 * Start a "getty" running on the console...
1453 *****************************************************************************/
1455 #if defined (_AIX) && defined (_POWER) || defined (__osf__)
1456 #define GETTYPATH "/usr/sbin/getty"
1457 #elif !defined (__apollo)
1458 #define GETTYPATH "/etc/getty"
1462 StartGetty( struct display *d )
1468 Debug ("StartGetty(): %s\n", d->name);
1470 bzero(&status, sizeof(waitType));
1472 * ensure that server is known dead...
1477 #if !defined(GETTYPATH)
1482 * check to see if we have a valid device (at least a non-null name)...
1485 if ( d->gettyLine &&
1486 (strlen(d->gettyLine) > 0) &&
1487 (strcmp(d->gettyLine,"??") != 0) )
1494 * if there is already a getty running on the device, set up
1495 * to start watching it. When it exits, restart the server...
1498 if ( GettyRunning(d) ) {
1499 d->status = suspended; /* set up to restart server */
1500 wakeupTime = 0; /* enable polling */
1502 sleep(1); /* wait for fbconsole to go away */
1503 GettyMessage(d,1); /* print a help message */
1510 * there is no getty running on the device, try to start one...
1513 d->status = phoenix; /* set up to restart server */
1516 switch (pid = fork ()) {
1521 * do process accounting...
1523 Account(d, "LOGIN", NULL, getpid(), LOGIN_PROCESS, status);
1527 /* The tty argument for getty on AIX must be of the form "/dev/any tty"
1528 and so the following logic
1529 Raghu krovvidi 07.07.93
1531 strcpy(tynm,"/dev/");
1532 strcat(tynm,d->gettyLine);
1534 strcpy(tynm, d->gettyLine);
1537 Debug(" execing getty on %s\n",tynm);
1538 execl(GETTYPATH, "getty", tynm, d->gettySpeed, (char *)0);
1539 LogError ((unsigned char *)"Can not execute %s for %s: errno = %d\n",
1540 GETTYPATH, d->name, errno);
1542 exit (UNMANAGE_DISPLAY);
1545 Debug ("Fork of /etc/getty failed %s\n", d->name);
1546 LogError ((unsigned char *)"Can not fork to execute /etc/getty %s\n", d->name);
1553 Debug ("/etc/getty started on %s\n", d->name);
1556 #endif /* GETTYPATH not defined */
1560 /***************************************************************************
1564 * Print a message on the display device when going into No Windows mode.
1566 ***************************************************************************/
1569 GettyMessage( struct display *d, int msgnum )
1574 strcpy(buf,"/dev/");
1575 strcat(buf,d->gettyLine);
1577 if ( (tf = fopen (buf, "a")) != NULL) {
1579 "\r\n\r\n*****************************************************************************\r\n*\r\n");
1584 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS1_LABEL,MC_DEF_SUS1_LABEL));
1586 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS2_LABEL,MC_DEF_SUS2_LABEL));
1588 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_SUS3_LABEL,MC_DEF_SUS3_LABEL));
1594 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_RES_LABEL,MC_DEF_RES_LABEL));
1601 (char *)ReadCatalog(MC_LABEL_SET,MC_START_LBLDPY,MC_DEF_START_LBLDPY),
1604 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_WAIT_LABEL,MC_DEF_WAIT_LABEL));
1610 fprintf(tf,(char *)ReadCatalog(MC_LABEL_SET,MC_X_LABEL,MC_DEF_X_LABEL),
1618 "*****************************************************************************\r\n");
1626 /***************************************************************************
1630 * See if a getty process is running against the display device. This
1631 * routine may need to be rewritten on other platforms if a different
1632 * mechanism is needed to make the determination.
1634 * Output: TRUE == a login process is active on the requested device
1635 * FALSE == a login process is not active on the device.
1637 * Sets d->gettyState:
1638 * NONE - no getty running or don't care
1639 * LOGIN - getty running
1640 * USER - user logged in on getty
1642 * Note: The check for a getty process running is made by scanning
1643 * /etc/utmp, looking for a login process on the respective device.
1644 * However, the child Dtlogin spawned by the master Dtlogin to
1645 * handle this display also is a "login process" according to
1646 * /etc/utmp. It provides a login path and therefore must register
1647 * itself as so. If a getty is also running, there are actually two
1648 * login processes running against the same device at the same time.
1650 * The child Dtlogin dies before the scan of /etc/utmp is made.
1651 * Provided /etc/utmp is updated correctly, the Dtlogin entry will
1652 * be marked as dead and will not show up in the scan of /etc/utmp.
1653 ***************************************************************************/
1656 GettyRunning( struct display *d )
1658 struct utmp utmp; /* local struct for new entry */
1659 struct utmp *u; /* pointer to entry in utmp file */
1661 int rvalue; /* return value (TRUE or FALSE) */
1664 d->gettyState = DM_GETTY_NONE;
1667 * check to see if we have a valid device (at least a non-null name)...
1670 if ( d->gettyLine &&
1671 (strlen(d->gettyLine) > 0) &&
1672 (strcmp(d->gettyLine,"??") != 0) )
1678 bzero(&utmp, sizeof(struct utmp));
1681 if (!strcmp(d->gettyLine,"console")) {
1685 fd = open("/dev/console",O_RDONLY);
1686 ttynm = ttyname(fd);
1688 strcpy(utmp.ut_line,ttynm);
1692 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1695 strncpy(utmp.ut_line, d->gettyLine, sizeof(utmp.ut_line));
1698 Debug("Checking for a getty on line %s.\n", utmp.ut_line);
1704 while ( (u = getutent()) != NULL ) {
1706 if ((strncmp(u->ut_line, utmp.ut_line, sizeof(u->ut_line)) != 0) ||
1707 (strncmp(u->ut_id, d->utmpId, sizeof(u->ut_id)) == 0) )
1710 switch (u->ut_type) {
1712 case INIT_PROCESS: strcpy(buf, "INIT_PROCESS"); break;
1713 case LOGIN_PROCESS: strcpy(buf, "LOGIN_PROCESS"); break;
1714 case USER_PROCESS: strcpy(buf, "USER_PROCESS"); break;
1715 case DEAD_PROCESS: strcpy(buf, "DEAD_PROCESS"); break;
1716 default: strcpy(buf, "UNKNOWN"); break;
1719 Debug("Utmp info: id=%.4s, user=%s, line=%s, pid=%d, type=%s\n",
1720 u->ut_id, u->ut_user, u->ut_line, u->ut_pid, buf);
1722 if ( u->ut_type == INIT_PROCESS || u->ut_type == LOGIN_PROCESS) {
1723 d->gettyState = DM_GETTY_LOGIN;
1725 else if (wakeupTime <= 0 && u->ut_type == USER_PROCESS) {
1726 d->gettyState = DM_GETTY_USER;
1729 if (d->gettyState != DM_GETTY_NONE)
1742 /***************************************************************************
1746 * Check if enough time has elapsed since shutdown.
1748 * This is primarily to work with /etc/shutdown. When shutdown kills
1749 * dtlogin (/etc/killall), init immediately restarts it. Shutdown kills
1750 * it again and init restarts it. At each restart, the X-server may start
1751 * on the local display and then subsequently be killed. The user sees a
1752 * flashing screen and sometimes the console is left in an unreset state.
1754 * When Dtlogin shuts down, it touches the access time on the Xservers
1755 * file. (MarkShutdownTime()). This time is then used to determine if
1756 * sufficient time has elapsed before restarting.
1758 ***************************************************************************/
1761 CheckRestartTime( void )
1766 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1768 Debug("Checking restart time.\n");
1771 /* only those other systems are this slow :-) */
1772 sleeptime = 6 - (int) (time((time_t *) 0) - statb.st_atime);
1774 sleeptime = 30 - (int) (time((time_t *) 0) - statb.st_atime);
1777 if ( sleeptime > 30 ) sleeptime = 30;
1779 if ( sleeptime > 0 ) {
1780 Debug("Restarting too soon after shutdown. Sleeping %d seconds.\n",
1789 /***************************************************************************
1793 * Save the time when we shut down to check later for too fast of a restart.
1795 ***************************************************************************/
1798 MarkShutdownTime( void )
1801 struct utimbuf timebuf;
1803 if (servers[0] == '/' && stat(servers, &statb) != -1) {
1805 Debug("Marking shutdown time.\n");
1807 timebuf.actime = time((time_t *) 0 );
1808 timebuf.modtime = statb.st_mtime;
1810 if ( (utime(servers, &timebuf)) != 0 ) {
1811 Debug("MarkShutdownTime(): utime() error = %d\n", errno);
1817 /***************************************************************************
1821 * Make the default dt directory "/var/dt" if needed.
1823 ***************************************************************************/
1825 dtMakeDefaultDir( void )
1827 dtmkdir("/var", 0775);
1828 dtmkdir("/var/dt", 0755);
1829 dtmkdir("/var/dt/tmp", 0755);
1830 dtmkdir("/var/dt/appconfig", 0755);
1831 dtmkdir("/var/dt/appconfig/appmanager", 0755);
1835 dtmkdir(char *dir, mode_t dir_mode)
1837 struct stat file_status;
1839 if ( stat(dir, &file_status) != 0) {
1840 /** try to create it **/
1841 if ( mkdir(dir, dir_mode) == 0) {
1842 chmod(dir, dir_mode); /** since umask is non-zero **/
1843 Debug("Created dir %s\n", dir);
1845 LogError((unsigned char *)"Unable to create dir %s\n", dir);
1848 if ( (file_status.st_mode & dir_mode) != dir_mode) {
1849 /** try to set correct permissions **/
1850 if ( chmod(dir, file_status.st_mode | dir_mode) == 0) {
1851 Debug("Set permissions on %s\n", dir);
1853 LogError((unsigned char *)
1854 "Unable to set permissions on %s\n", dir);