1 //===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Created by Greg Clayton on 1/8/08. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "PseudoTerminal.h" 15 #include <stdlib.h> 16 #include <sys/ioctl.h> 17 #include <unistd.h> 18 19 //---------------------------------------------------------------------- 20 // PseudoTerminal constructor 21 //---------------------------------------------------------------------- 22 PseudoTerminal::PseudoTerminal() 23 : m_master_fd(invalid_fd), m_slave_fd(invalid_fd) {} 24 25 //---------------------------------------------------------------------- 26 // Destructor 27 // The master and slave file descriptors will get closed if they are 28 // valid. Call the ReleaseMasterFD()/ReleaseSlaveFD() member functions 29 // to release any file descriptors that are needed beyond the lifespan 30 // of this object. 31 //---------------------------------------------------------------------- 32 PseudoTerminal::~PseudoTerminal() { 33 CloseMaster(); 34 CloseSlave(); 35 } 36 37 //---------------------------------------------------------------------- 38 // Close the master file descriptor if it is valid. 39 //---------------------------------------------------------------------- 40 void PseudoTerminal::CloseMaster() { 41 if (m_master_fd > 0) { 42 ::close(m_master_fd); 43 m_master_fd = invalid_fd; 44 } 45 } 46 47 //---------------------------------------------------------------------- 48 // Close the slave file descriptor if it is valid. 49 //---------------------------------------------------------------------- 50 void PseudoTerminal::CloseSlave() { 51 if (m_slave_fd > 0) { 52 ::close(m_slave_fd); 53 m_slave_fd = invalid_fd; 54 } 55 } 56 57 //---------------------------------------------------------------------- 58 // Open the first available pseudo terminal with OFLAG as the 59 // permissions. The file descriptor is store in the m_master_fd member 60 // variable and can be accessed via the MasterFD() or ReleaseMasterFD() 61 // accessors. 62 // 63 // Suggested value for oflag is O_RDWR|O_NOCTTY 64 // 65 // RETURNS: 66 // Zero when successful, non-zero indicating an error occurred. 67 //---------------------------------------------------------------------- 68 PseudoTerminal::Error PseudoTerminal::OpenFirstAvailableMaster(int oflag) { 69 // Open the master side of a pseudo terminal 70 m_master_fd = ::posix_openpt(oflag); 71 if (m_master_fd < 0) { 72 return err_posix_openpt_failed; 73 } 74 75 // Grant access to the slave pseudo terminal 76 if (::grantpt(m_master_fd) < 0) { 77 CloseMaster(); 78 return err_grantpt_failed; 79 } 80 81 // Clear the lock flag on the slave pseudo terminal 82 if (::unlockpt(m_master_fd) < 0) { 83 CloseMaster(); 84 return err_unlockpt_failed; 85 } 86 87 return success; 88 } 89 90 //---------------------------------------------------------------------- 91 // Open the slave pseudo terminal for the current master pseudo 92 // terminal. A master pseudo terminal should already be valid prior to 93 // calling this function (see PseudoTerminal::OpenFirstAvailableMaster()). 94 // The file descriptor is stored in the m_slave_fd member variable and 95 // can be accessed via the SlaveFD() or ReleaseSlaveFD() accessors. 96 // 97 // RETURNS: 98 // Zero when successful, non-zero indicating an error occurred. 99 //---------------------------------------------------------------------- 100 PseudoTerminal::Error PseudoTerminal::OpenSlave(int oflag) { 101 CloseSlave(); 102 103 // Open the master side of a pseudo terminal 104 const char *slave_name = SlaveName(); 105 106 if (slave_name == NULL) 107 return err_ptsname_failed; 108 109 m_slave_fd = ::open(slave_name, oflag); 110 111 if (m_slave_fd < 0) 112 return err_open_slave_failed; 113 114 return success; 115 } 116 117 //---------------------------------------------------------------------- 118 // Get the name of the slave pseudo terminal. A master pseudo terminal 119 // should already be valid prior to calling this function (see 120 // PseudoTerminal::OpenFirstAvailableMaster()). 121 // 122 // RETURNS: 123 // NULL if no valid master pseudo terminal or if ptsname() fails. 124 // The name of the slave pseudo terminal as a NULL terminated C string 125 // that comes from static memory, so a copy of the string should be 126 // made as subsequent calls can change this value. 127 //---------------------------------------------------------------------- 128 const char *PseudoTerminal::SlaveName() const { 129 if (m_master_fd < 0) 130 return NULL; 131 return ::ptsname(m_master_fd); 132 } 133 134 //---------------------------------------------------------------------- 135 // Fork a child process that and have its stdio routed to a pseudo 136 // terminal. 137 // 138 // In the parent process when a valid pid is returned, the master file 139 // descriptor can be used as a read/write access to stdio of the 140 // child process. 141 // 142 // In the child process the stdin/stdout/stderr will already be routed 143 // to the slave pseudo terminal and the master file descriptor will be 144 // closed as it is no longer needed by the child process. 145 // 146 // This class will close the file descriptors for the master/slave 147 // when the destructor is called, so be sure to call ReleaseMasterFD() 148 // or ReleaseSlaveFD() if any file descriptors are going to be used 149 // past the lifespan of this object. 150 // 151 // RETURNS: 152 // in the parent process: the pid of the child, or -1 if fork fails 153 // in the child process: zero 154 //---------------------------------------------------------------------- 155 156 pid_t PseudoTerminal::Fork(PseudoTerminal::Error &error) { 157 pid_t pid = invalid_pid; 158 error = OpenFirstAvailableMaster(O_RDWR | O_NOCTTY); 159 160 if (error == 0) { 161 // Successfully opened our master pseudo terminal 162 163 pid = ::fork(); 164 if (pid < 0) { 165 // Fork failed 166 error = err_fork_failed; 167 } else if (pid == 0) { 168 // Child Process 169 ::setsid(); 170 171 error = OpenSlave(O_RDWR); 172 if (error == 0) { 173 // Successfully opened slave 174 // We are done with the master in the child process so lets close it 175 CloseMaster(); 176 177 #if defined(TIOCSCTTY) 178 // Acquire the controlling terminal 179 if (::ioctl(m_slave_fd, TIOCSCTTY, (char *)0) < 0) 180 error = err_failed_to_acquire_controlling_terminal; 181 #endif 182 // Duplicate all stdio file descriptors to the slave pseudo terminal 183 if (::dup2(m_slave_fd, STDIN_FILENO) != STDIN_FILENO) 184 error = error ? error : err_dup2_failed_on_stdin; 185 if (::dup2(m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) 186 error = error ? error : err_dup2_failed_on_stdout; 187 if (::dup2(m_slave_fd, STDERR_FILENO) != STDERR_FILENO) 188 error = error ? error : err_dup2_failed_on_stderr; 189 } 190 } else { 191 // Parent Process 192 // Do nothing and let the pid get returned! 193 } 194 } 195 return pid; 196 } 197