//---------------------------------------------------------------------- // Open the first available pseudo terminal with OFLAG as the // permissions. The file descriptor is store in the m_master_fd member // variable and can be accessed via the MasterFD() or ReleaseMasterFD() // accessors. // // Suggested value for oflag is O_RDWR|O_NOCTTY // // RETURNS: // Zero when successful, non-zero indicating an error occurred. //---------------------------------------------------------------------- PseudoTerminal::Error PseudoTerminal::OpenFirstAvailableMaster(int oflag) { // Open the master side of a pseudo terminal m_master_fd = ::posix_openpt (oflag); if (m_master_fd < 0) { return err_posix_openpt_failed; } // Grant access to the slave pseudo terminal if (::grantpt (m_master_fd) < 0) { CloseMaster(); return err_grantpt_failed; } // Clear the lock flag on the slave pseudo terminal if (::unlockpt (m_master_fd) < 0) { CloseMaster(); return err_unlockpt_failed; } return success; }
pid_t PseudoTerminal::Fork(PseudoTerminal::Error& error) { pid_t pid = invalid_pid; error = OpenFirstAvailableMaster (O_RDWR|O_NOCTTY); if (error == 0) { // Successfully opened our master pseudo terminal pid = ::fork (); if (pid < 0) { // Fork failed error = err_fork_failed; } else if (pid == 0) { // Child Process ::setsid(); error = OpenSlave (O_RDWR); if (error == 0) { // Successfully opened slave // We are done with the master in the child process so lets close it CloseMaster (); #if defined (TIOCSCTTY) // Acquire the controlling terminal if (::ioctl (m_slave_fd, TIOCSCTTY, (char *)0) < 0) error = err_failed_to_acquire_controlling_terminal; #endif // Duplicate all stdio file descriptors to the slave pseudo terminal if (::dup2 (m_slave_fd, STDIN_FILENO) != STDIN_FILENO) error = error ? error : err_dup2_failed_on_stdin; if (::dup2 (m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) error = error ? error : err_dup2_failed_on_stdout; if (::dup2 (m_slave_fd, STDERR_FILENO) != STDERR_FILENO) error = error ? error : err_dup2_failed_on_stderr; } } else { // Parent Process // Do nothing and let the pid get returned! } } return pid; }
// Destructor // The master and slave file descriptors will get closed if they are // valid. Call the ReleaseMasterFD()/ReleaseSlaveFD() member functions // to release any file descriptors that are needed beyond the lifespan // of this object. PseudoTerminal::~PseudoTerminal() { CloseMaster(); CloseSlave(); }