void signal_unblock_winch (void) { #if defined (SIGWINCH) sigwinch_block_count--; if (sigwinch_block_count == 0) UNBLOCK_SIGNAL (SIGWINCH); #endif }
static int allocate_master(const char ** slave_name, const char** clone) { int master_fd = -1; static const char * const clones[] = /* Different pty master clone devices */ { "/dev/ptmx", /* Various systems */ "/dev/ptm/clone", /* HPUX */ "/dev/ptc", /* AIX */ "/dev/ptmx_bsd" /* Tru64 */ }; #ifdef HAVE_GETPT /* glibc */ master_fd = getpt (); if (master_fd >= 0) return master_fd; #endif /* HAVE_GETPT */ #if defined(HAVE_OPENPTY) /* BSD, Tru64, glibc */ { int slave_fd = -1; int rc; BLOCK_SIGNAL (SIGCHLD); rc = openpty (&master_fd, &slave_fd, NULL, NULL, NULL); UNBLOCK_SIGNAL (SIGCHLD); if (rc == 0) { *slave_name = ttyname (slave_fd); retry_close (slave_fd); return master_fd; } else { if (master_fd >= 0) retry_close (master_fd); if (slave_fd >= 0) retry_close (slave_fd); } } #endif /* HAVE_OPENPTY */ #if defined(HAVE__GETPTY) && defined (O_NDELAY) /* SGI */ master_fd = -1; BLOCK_SIGNAL (SIGCHLD); *slave_name = _getpty (&master_fd, O_RDWR | O_NDELAY, 0600, 0); UNBLOCK_SIGNAL (SIGCHLD); if (master_fd >= 0 && *slave_name != NULL) return master_fd; #endif /* HAVE__GETPTY */ /* Master clone devices are available on most systems */ { int i; for (i = 0; i < countof (clones); i++) { *clone = clones[i]; master_fd = open ((char *) *clone, // TODO: retry open O_RDWR | O_NONBLOCK, 0); if (master_fd >= 0) return master_fd; } *clone = NULL; } return -1; }
/* Open an available pty, returning a file descriptor. Return -1 on failure. */ s48_ref_t allocate_pty(s48_call_t call) { /* Unix98 standardized grantpt, unlockpt, and ptsname, but not the functions required to open a master pty in the first place :-( Modern Unix systems all seems to have convenience methods to open a master pty fd in one function call, but there is little agreement on how to do it. allocate_pty() tries all the different known easy ways of opening a pty. In case of failure, we resort to the old BSD-style pty grovelling code in allocate_pty_the_old_fashioned_way(). */ int master_fd = -1; const char *slave_name = NULL; const char* clone = NULL; int off = 0; s48_ref_t scm_slave_name = s48_unspecific_2(call); master_fd = allocate_master(&slave_name, &clone); if (master_fd == -1) return s48_false_2(call); if (slave_name == NULL){ slave_name = allocate_slave_name(master_fd, clone); if (slave_name == NULL){ retry_close (master_fd); return s48_false_2(call); } } scm_slave_name = s48_enter_byte_string_2(call, (char *) slave_name); #ifdef TIOCPKT /* In some systems (Linux through 2.0.0, at least), packet mode doesn't get cleared when a pty is closed, so we need to clear it here. Linux pre2.0.13 contained an attempted fix for this (from Ted Ts'o, [email protected]), but apparently it messed up rlogind and telnetd, so he removed the fix in pre2.0.14. - [email protected] */ ioctl (master_fd, TIOCPKT, (char *)&off); #endif /* TIOCPKT */ /* We jump through some hoops to frob the pty. It's not obvious that checking the return code here is useful. */ /* "The grantpt() function will fail if it is unable to successfully invoke the setuid root program. It may also fail if the application has installed a signal handler to catch SIGCHLD signals." */ #if defined (HAVE_GRANTPT) || defined (HAVE_UNLOCKPT) BLOCK_SIGNAL (SIGCHLD); #if defined (HAVE_GRANTPT) grantpt (master_fd); #endif /* HAVE_GRANTPT */ #if defined (HAVE_UNLOCKPT) unlockpt (master_fd); #endif UNBLOCK_SIGNAL (SIGCHLD); #endif /* HAVE_GRANTPT || HAVE_UNLOCKPT */ fcntl(master_fd, F_SETFL, O_NONBLOCK); return s48_cons_2(call, s48_enter_long_2(call, master_fd), scm_slave_name); }
static RETSIGTYPE info_signal_proc (int sig) { signal_info *old_signal_handler = NULL; #if !defined (HAVE_SIGACTION) /* best effort: first increment this counter and later block signals */ if (term_conf_busy) return; term_conf_busy++; #if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK) { sigset_t nvar, ovar; sigemptyset (&nvar); mask_termsig (&nvar); sigprocmask (SIG_BLOCK, &nvar, &ovar); } #endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */ #endif /* !HAVE_SIGACTION */ switch (sig) { #if defined (SIGTSTP) case SIGTSTP: case SIGTTOU: case SIGTTIN: #endif #if defined (SIGQUIT) case SIGQUIT: #endif #if defined (SIGINT) case SIGINT: #endif { #if defined (SIGTSTP) if (sig == SIGTSTP) old_signal_handler = &old_TSTP; if (sig == SIGTTOU) old_signal_handler = &old_TTOU; if (sig == SIGTTIN) old_signal_handler = &old_TTIN; #endif /* SIGTSTP */ #if defined (SIGQUIT) if (sig == SIGQUIT) old_signal_handler = &old_QUIT; #endif /* SIGQUIT */ #if defined (SIGINT) if (sig == SIGINT) old_signal_handler = &old_INT; #endif /* SIGINT */ /* For stop signals, restore the terminal IO, leave the cursor at the bottom of the window, and stop us. */ terminal_goto_xy (0, screenheight - 1); terminal_clear_to_eol (); fflush (stdout); terminal_unprep_terminal (); restore_termsig (sig, old_signal_handler); UNBLOCK_SIGNAL (sig); kill (getpid (), sig); /* The program is returning now. Restore our signal handler, turn on terminal handling, redraw the screen, and place the cursor where it belongs. */ terminal_prep_terminal (); set_termsig (sig, old_signal_handler); /* window size might be changed while sleeping */ reset_info_window_sizes (); } break; #if defined (SIGWINCH) || defined (SIGUSR1) #ifdef SIGWINCH case SIGWINCH: #endif #ifdef SIGUSR1 case SIGUSR1: #endif { /* Turn off terminal IO, tell our parent that the window has changed, then reinitialize the terminal and rebuild our windows. */ #ifdef SIGWINCH if (sig == SIGWINCH) old_signal_handler = &old_WINCH; #endif #ifdef SIGUSR1 if (sig == SIGUSR1) old_signal_handler = &old_USR1; #endif terminal_goto_xy (0, 0); fflush (stdout); terminal_unprep_terminal (); /* needless? */ restore_termsig (sig, old_signal_handler); UNBLOCK_SIGNAL (sig); kill (getpid (), sig); /* After our old signal handler returns... */ set_termsig (sig, old_signal_handler); /* needless? */ terminal_prep_terminal (); reset_info_window_sizes (); } break; #endif /* SIGWINCH || SIGUSR1 */ } #if !defined (HAVE_SIGACTION) /* at this time it is safer to perform unblock after decrement */ term_conf_busy--; #if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK) { sigset_t nvar, ovar; sigemptyset (&nvar); mask_termsig (&nvar); sigprocmask (SIG_UNBLOCK, &nvar, &ovar); } #endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */ #endif /* !HAVE_SIGACTION */ }