static int exec_args ( char *filename, char **args) { pid_t pid; waitType status; if (!filename) return -1; if (filename[0] != '/') { fprintf (stderr, "%s: attempt to execute program with relative pathname: %s\n", ProgramName, filename); return -1; } if (access (filename, X_OK) != 0) return -1; switch (pid = vfork ()) { case -1: /* error */ return -1; case 0: /* child */ execv (filename, args); _exit (1); /* NOTREACHED */ default: /* parent */ while (wait (&status) != pid) ; } return waitCode (status); }
void WaitForChild(void) { int pid; struct display *d; waitType status; sigset_t mask, omask; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigaddset(&mask, SIGHUP); sigprocmask(SIG_BLOCK, &mask, &omask); WDMDebug("signals blocked\n"); if (!ChildReady && !Rescan) sigsuspend(&omask); ChildReady = 0; sigprocmask(SIG_SETMASK, &omask, (sigset_t *) NULL); while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { WDMDebug("Manager wait returns pid: %d sig %d core %d code %d\n", pid, waitSig(status), waitCore(status), waitCode(status)); if (autoRescan.i) RescanIfMod(); /* SUPPRESS 560 */ if ((d = FindDisplayByPid(pid))) { d->pid = -1; switch (waitVal(status)) { case UNMANAGE_DISPLAY: WDMDebug("Display exited with UNMANAGE_DISPLAY\n"); StopDisplay(d); break; case OBEYSESS_DISPLAY: d->startTries = 0; WDMDebug("Display exited with OBEYSESS_DISPLAY\n"); if (d->displayType.lifetime != Permanent || d->status == zombie) StopDisplay(d); else RestartDisplay(d, FALSE); break; default: WDMDebug("Display exited with unknown status %d\n", waitVal(status)); WDMError("Unknown session exit code %d from process %d\n", waitVal(status), pid); StopDisplay(d); break; case OPENFAILED_DISPLAY: WDMDebug("Display exited with OPENFAILED_DISPLAY, try %d of %d\n", d->startTries, d->startAttempts); WDMError("Display %s cannot be opened\n", d->name); /* * no display connection was ever made, tell the * terminal that the open attempt failed */ #ifdef XDMCP if (d->displayType.origin == FromXDMCP) SendFailed(d, "Cannot open display"); #endif if (d->displayType.origin == FromXDMCP || d->status == zombie || ++d->startTries >= d->startAttempts) { WDMError("Display %s is being disabled\n", d->name); StopDisplay(d); } else { RestartDisplay(d, TRUE); } break; case RESERVER_DISPLAY: d->startTries = 0; WDMDebug("Display exited with RESERVER_DISPLAY\n"); if (d->displayType.origin == FromXDMCP || d->status == zombie) StopDisplay(d); else RestartDisplay(d, TRUE); { Time_t Time; time(&Time); WDMDebug("time %i %i\n", (int)Time, (int)d->lastCrash); if (d->lastCrash && ((Time - d->lastCrash) < XDM_BROKEN_INTERVAL)) { WDMDebug("Server crash frequency too high:" " removing display %s\n", d->name); WDMError("Server crash rate too high:" " removing display %s\n", d->name); RemoveDisplay(d); } else d->lastCrash = Time; } break; case waitCompose(SIGTERM, 0, 0): WDMDebug("Display exited on SIGTERM, try %d of %d\n", d->startTries, d->startAttempts); if (d->displayType.origin == FromXDMCP || d->status == zombie || ++d->startTries >= d->startAttempts) { WDMError("Display %s is being disabled\n", d->name); StopDisplay(d); } else RestartDisplay(d, TRUE); break; case REMANAGE_DISPLAY: d->startTries = 0; WDMDebug("Display exited with REMANAGE_DISPLAY\n"); /* * XDMCP will restart the session if the display * requests it */ if (d->displayType.origin == FromXDMCP || d->status == zombie) StopDisplay(d); else RestartDisplay(d, FALSE); break; } } /* SUPPRESS 560 */ else if ((d = FindDisplayByServerPid(pid))) { d->serverPid = -1; switch (d->status) { case zombie: WDMDebug("Zombie server reaped, removing display %s\n", d->name); RemoveDisplay(d); break; case phoenix: WDMDebug("Phoenix server arises, restarting display %s\n", d->name); d->status = notRunning; break; case running: WDMDebug("Server for display %s terminated unexpectedly, status %d %d\n", d->name, waitVal(status), status); WDMError("Server for display %s terminated unexpectedly: %d\n", d->name, waitVal(status)); d->status = notRunning; if (d->pid != -1) { WDMDebug("Terminating session pid %d\n", d->pid); TerminateProcess(d->pid, SIGTERM); } break; case notRunning: WDMDebug("Server exited for notRunning session on display %s\n", d->name); break; } } else { WDMDebug("Unknown child termination, status %d\n", waitVal(status)); } } StartDisplays(); }
void WaitForChild (void) { pid_t pid; struct display *d; waitType status; sigset_t mask, omask; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigaddset(&mask, SIGHUP); sigprocmask(SIG_BLOCK, &mask, &omask); Debug ("signals blocked\n"); if (!ChildReady && !Rescan) sigsuspend(&omask); ChildReady = 0; sigprocmask(SIG_SETMASK, &omask, (sigset_t *)NULL); while ((pid = waitpid (-1, &status, WNOHANG)) > 0) { Debug ("Manager wait returns pid: %d sig %d core %d code %d\n", pid, waitSig(status), waitCore(status), waitCode(status)); if (autoRescan) RescanIfMod (); /* SUPPRESS 560 */ if ((d = FindDisplayByPid (pid))) { d->pid = -1; switch (waitVal (status)) { case UNMANAGE_DISPLAY: Debug ("Display exited with UNMANAGE_DISPLAY\n"); StopDisplay (d); break; case OBEYSESS_DISPLAY: d->startTries = 0; d->reservTries = 0; Debug ("Display exited with OBEYSESS_DISPLAY\n"); if (d->status == zombie) StopDisplay (d); else RestartDisplay (d, FALSE); break; case OPENFAILED_DISPLAY: Debug ("Display exited with OPENFAILED_DISPLAY, try %d of %d\n", d->startTries, d->startAttempts); LogError ("Display %s cannot be opened\n", d->name); /* * no display connection was ever made, tell the * terminal that the open attempt failed */ if (d->status == zombie || ++d->startTries >= d->startAttempts) { LogError ("Display %s is being disabled\n", d->name); StopDisplay (d); } else { RestartDisplay (d, TRUE); } break; case RESERVER_DISPLAY: d->startTries = 0; Debug ("Display exited with RESERVER_DISPLAY\n"); if (d->status == zombie) StopDisplay(d); else { Time_t now; int crash; time(&now); crash = d->lastReserv && ((now - d->lastReserv) < XDM_BROKEN_INTERVAL); Debug("time %lli %lli try %i of %i%s\n", (long long)now, (long long)d->lastReserv, d->reservTries, d->reservAttempts, crash ? " crash" : ""); if (!crash) d->reservTries = 0; if (crash && ++d->reservTries >= d->reservAttempts) { const char *msg = "Server crash frequency too high: stopping display"; Debug("%s %s\n", msg, d->name); LogError("%s %s\n", msg, d->name); /* For a local X server either: * 1. The server exit was returned by waitpid(). So * serverPid==-1 => StopDisplay() calls RemoveDisplay() * * 2. The server is in zombie state or still running. So * serverPid>1 => StopDisplay() * a. sets status=zombie, * b. kills the server. * The next waitpid() returns this zombie server pid * and the 'case zombie:' below then calls * RemoveDisplay(). */ StopDisplay(d); } else { RestartDisplay(d, TRUE); } d->lastReserv = now; } break; case waitCompose (SIGTERM,0,0): Debug ("Display exited on SIGTERM, try %d of %d\n", d->startTries, d->startAttempts); if (d->status == zombie || ++d->startTries >= d->startAttempts) { /* * During normal xdm shutdown, killed local X servers * can be zombies; this is not an error. */ if (d->status == zombie && (d->startTries < d->startAttempts)) LogInfo ("display %s is being disabled\n", d->name); else LogError ("display %s is being disabled\n", d->name); StopDisplay(d); } else RestartDisplay (d, TRUE); break; case REMANAGE_DISPLAY: d->startTries = 0; Debug ("Display exited with REMANAGE_DISPLAY\n"); /* * XDMCP will restart the session if the display * requests it */ if (d->status == zombie) StopDisplay(d); else RestartDisplay (d, FALSE); break; default: Debug ("Display exited with unknown status %d\n", waitVal(status)); LogError ("Unknown session exit code %d from process %d\n", waitVal (status), pid); StopDisplay (d); break; } } /* SUPPRESS 560 */ else if ((d = FindDisplayByServerPid (pid))) { d->serverPid = -1; switch (d->status) { case zombie: Debug ("Zombie server reaped, removing display %s\n", d->name); RemoveDisplay (d); break; case phoenix: Debug ("Phoenix server arises, restarting display %s\n", d->name); d->status = notRunning; break; case running: Debug ("Server for display %s terminated unexpectedly, status %d %d\n", d->name, waitVal (status), status); LogError ("Server for display %s terminated unexpectedly: %d\n", d->name, waitVal (status)); if (d->pid != -1) { Debug ("Terminating session pid %d\n", d->pid); kill (d->pid, SIGTERM); } break; case notRunning: Debug ("Server exited for notRunning session on display %s\n", d->name); break; } } else { Debug ("Unknown child termination, status %d\n", waitVal (status)); } } StartDisplays (); }
/*************************************************************************** * * Account * * update utmp/wtmp files. ***************************************************************************/ void Account( struct display *d, char *user, char *line, pid_t pid, #if NeedWidePrototypes int type, #else short type, #endif /* NeedWidePrototypes */ waitType exitcode ) { #if !defined(CSRG_BASED) /* we cannot do this on BSD ... */ struct utmp utmp; /* local struct for new entry */ struct utmp *u; /* pointer to entry in utmp file */ int fd; char buf[32]; char* user_str = user ? user : "******"; char* line_str = line ? line : "NULL"; #ifdef __PASSWD_ETC struct rtmp rtmp; struct rtmp *r; int tty_slot; int rtmp_fd; #endif if (d->utmpId == NULL) return; switch (type) { case INIT_PROCESS: strcpy(buf, "INIT_PROCESS"); break; case LOGIN_PROCESS: strcpy(buf, "LOGIN_PROCESS"); break; case USER_PROCESS: strcpy(buf, "USER_PROCESS"); break; case DEAD_PROCESS: strcpy(buf, "DEAD_PROCESS"); break; default: strcpy(buf, "UNKNOWN"); break; } Debug("Account: id=%s, user=%s, line=%s, pid=%d, type=%s\n", d->utmpId, user_str, line_str, pid, buf); #ifdef PAM PamAccounting("dtlogin", d->name, d->utmpId, user, line, pid, type, exitcode); #else # ifdef SUNAUTH solaris_accounting("dtlogin", d->name, d->utmpId, user, line, pid, type, exitcode); # endif #endif #ifdef sun return; #else bzero(&utmp, sizeof(struct utmp)); strncpy(utmp.ut_id, d->utmpId, sizeof(u->ut_id)); utmp.ut_type = LOGIN_PROCESS; setutent(); if ( (u = getutid(&utmp)) == NULL ) u = &utmp; /* * make sure process ID's match if this is DEAD_PROCESS... * don't update an already DEAD_PROCESS... */ if ((type == DEAD_PROCESS && pid != 0 && u->ut_pid != pid) || (type == DEAD_PROCESS && u->ut_type == DEAD_PROCESS) ) { endutent(); return; } /* * fill in required fields of utmp structure... * * Note: for USER_PRCESS the "e_exit" field is overloaded to contain * the method for counting this user. This is used later to * determine if restricted user licenses have been exceeded. * Currently, an unlimited number of foreign displays can log in. */ if (user) strncpy(u->ut_user, user, sizeof(u->ut_user)); if (line) { #ifdef _AIX /* For AIX the Init process writes the exact mapped device name for console to the utmp file (like hft/0), if a getty on /dev/console record exists in the Inittab file.Hitherto, we need to have a similar logic to make sure for having the correct entry in the utmp file in order for the correct operation of the GettyRunning function. It should be noted that by having the correct value in the d->gettyLine field, the utmp file eventuallly updated by the Account function in dm.c will have the right value. And thus the GettyRunning function returns the appropriate value. So, it is important that the following logic be included here for AIX platform only. Raghu Krovvidi 07.06.93 */ if (!strcmp(line,"console")) { char *ttynm; int fd=0; fd = open("/dev/console",O_RDONLY); ttynm = ttyname(fd); ttynm += 5; strcpy(u->ut_line,ttynm); close(fd); } else strncpy(u->ut_line, line, sizeof(u->ut_line)); #else strncpy(u->ut_line, line, sizeof(u->ut_line)); #endif } if (pid ) u->ut_pid = pid; if (type) { u->ut_type = type; if (type == DEAD_PROCESS) { u->ut_exit.e_termination = waitSig(exitcode); u->ut_exit.e_exit = waitCode(exitcode); #ifndef SVR4 (void) memset((char *) u->ut_host, '\0', sizeof(u->ut_host)); #endif } if (type == LOGIN_PROCESS && d->displayType.location != Local ) { #ifndef SVR4 strncpy(u->ut_host, d->name, sizeof(u->ut_host)); #endif #ifdef __hpux u->ut_addr = 0; #endif } if (type == USER_PROCESS) u->ut_exit.e_exit = (d->displayType.location == Local ? 1 : 0 ); } (void) time(&u->ut_time); /* * write to utmp... * * (Do not close utmp yet. If "u" points to the static structure, it is * cleared upon close. This does not bode well for the following write * to wtmp!) */ pututline(u); /* * write the same entry to wtmp... */ if ((fd = open(WTMP_FILE, O_WRONLY | O_APPEND)) >= 0) { write(fd, u, sizeof(utmp)); close(fd); } /* * close utmp... */ endutent(); #ifdef __PASSWD_ETC /* Now fill in the "rgy utmp" struct */ if (line) strncpy(rtmp.rt_line, u->ut_line, sizeof(u->ut_line)); bzero(rtmp.rt_host, sizeof(rtmp.rt_host)); rtmp.rt_time = u->ut_time; r = &rtmp; /* Write entry to rtmp */ tty_slot = ttyslot(); if (tty_slot > 0 && (rtmp_fd = open("/etc/rtmp", O_WRONLY|O_CREAT, 0644)) >= 0) { lseek(rtmp_fd, (long) (tty_slot * sizeof(struct rtmp)), 0); write(rtmp_fd, (char *) r, sizeof(struct rtmp)); close(rtmp_fd); } #endif #if defined(AIXV3) && !defined(_POWER) /* Log the lastlogin data .. RK 09.13.93 */ /** in AIX 4.1 this is taken care of during authentication **/ if(type == USER_PROCESS) { int loginType; char tempTtyName[128]; char *hostname; GetLoginInfo(d, &loginType, tempTtyName, &hostname); time(&last_login.stime); if(line) { Debug("tty_last_login is (line=%s)\n",line); last_login.stty = (char *)malloc(strlen(line) + 1); strcpy(last_login.stty,line); } else { last_login.stty = (char *)malloc(strlen(tempTtyName) + 1); strcpy(last_login.stty,tempTtyName); } last_login.shost = (char *) malloc (MAXHOSTNAMELEN); if (hostname == NULL) { gethostname (last_login.shost , MAXHOSTNAMELEN); } else { strncpy(last_login.shost, hostname, MAXHOSTNAMELEN); last_login.shost[MAXHOSTNAMELEN -1] = '\0'; } Debug("logging lastlogin entry (user=%s)\n",user); dt_lastlogin(user,&last_login); free(last_login.stty); free(last_login.shost); } #endif #endif /* !sun */ #endif /* !CSRG_BASED */ }