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#include "lldb/Utility/PseudoTerminal.h" 11 12#include <errno.h> 13#include <stdlib.h> 14#include <string.h> 15#include <stdio.h> 16#if defined(TIOCSCTTY) 17#include <sys/ioctl.h> 18#endif 19 20using namespace lldb_utility; 21 22//---------------------------------------------------------------------- 23// PseudoTerminal constructor 24//---------------------------------------------------------------------- 25PseudoTerminal::PseudoTerminal () : 26 m_master_fd(invalid_fd), 27 m_slave_fd(invalid_fd) 28{ 29} 30 31//---------------------------------------------------------------------- 32// Destructor 33// 34// The destructor will close the master and slave file descriptors 35// if they are valid and ownwership has not been released using the 36// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor() 37// member functions. 38//---------------------------------------------------------------------- 39PseudoTerminal::~PseudoTerminal () 40{ 41 CloseMasterFileDescriptor(); 42 CloseSlaveFileDescriptor(); 43} 44 45//---------------------------------------------------------------------- 46// Close the master file descriptor if it is valid. 47//---------------------------------------------------------------------- 48void 49PseudoTerminal::CloseMasterFileDescriptor () 50{ 51 if (m_master_fd >= 0) 52 { 53 ::close (m_master_fd); 54 m_master_fd = invalid_fd; 55 } 56} 57 58//---------------------------------------------------------------------- 59// Close the slave file descriptor if it is valid. 60//---------------------------------------------------------------------- 61void 62PseudoTerminal::CloseSlaveFileDescriptor () 63{ 64 if (m_slave_fd >= 0) 65 { 66 ::close (m_slave_fd); 67 m_slave_fd = invalid_fd; 68 } 69} 70 71//---------------------------------------------------------------------- 72// Open the first available pseudo terminal with OFLAG as the 73// permissions. The file descriptor is stored in this object and can 74// be accessed with the MasterFileDescriptor() accessor. The 75// ownership of the master file descriptor can be released using 76// the ReleaseMasterFileDescriptor() accessor. If this object has 77// a valid master files descriptor when its destructor is called, it 78// will close the master file descriptor, therefore clients must 79// call ReleaseMasterFileDescriptor() if they wish to use the master 80// file descriptor after this object is out of scope or destroyed. 81// 82// RETURNS: 83// Zero when successful, non-zero indicating an error occurred. 84//---------------------------------------------------------------------- 85bool 86PseudoTerminal::OpenFirstAvailableMaster (int oflag, char *error_str, size_t error_len) 87{ 88 if (error_str) 89 error_str[0] = '\0'; 90 91 // Open the master side of a pseudo terminal 92 m_master_fd = ::posix_openpt (oflag); 93 if (m_master_fd < 0) 94 { 95 if (error_str) 96 ::strerror_r (errno, error_str, error_len); 97 return false; 98 } 99 100 // Grant access to the slave pseudo terminal 101 if (::grantpt (m_master_fd) < 0) 102 { 103 if (error_str) 104 ::strerror_r (errno, error_str, error_len); 105 CloseMasterFileDescriptor (); 106 return false; 107 } 108 109 // Clear the lock flag on the slave pseudo terminal 110 if (::unlockpt (m_master_fd) < 0) 111 { 112 if (error_str) 113 ::strerror_r (errno, error_str, error_len); 114 CloseMasterFileDescriptor (); 115 return false; 116 } 117 118 return true; 119} 120 121//---------------------------------------------------------------------- 122// Open the slave pseudo terminal for the current master pseudo 123// terminal. A master pseudo terminal should already be valid prior to 124// calling this function (see OpenFirstAvailableMaster()). 125// The file descriptor is stored this object's member variables and can 126// be accessed via the GetSlaveFileDescriptor(), or released using the 127// ReleaseSlaveFileDescriptor() member function. 128// 129// RETURNS: 130// Zero when successful, non-zero indicating an error occurred. 131//---------------------------------------------------------------------- 132bool 133PseudoTerminal::OpenSlave (int oflag, char *error_str, size_t error_len) 134{ 135 if (error_str) 136 error_str[0] = '\0'; 137 138 CloseSlaveFileDescriptor(); 139 140 // Open the master side of a pseudo terminal 141 const char *slave_name = GetSlaveName (error_str, error_len); 142 143 if (slave_name == NULL) 144 return false; 145 146 m_slave_fd = ::open (slave_name, oflag); 147 148 if (m_slave_fd < 0) 149 { 150 if (error_str) 151 ::strerror_r (errno, error_str, error_len); 152 return false; 153 } 154 155 return true; 156} 157 158 159 160//---------------------------------------------------------------------- 161// Get the name of the slave pseudo terminal. A master pseudo terminal 162// should already be valid prior to calling this function (see 163// OpenFirstAvailableMaster()). 164// 165// RETURNS: 166// NULL if no valid master pseudo terminal or if ptsname() fails. 167// The name of the slave pseudo terminal as a NULL terminated C string 168// that comes from static memory, so a copy of the string should be 169// made as subsequent calls can change this value. 170//---------------------------------------------------------------------- 171const char* 172PseudoTerminal::GetSlaveName (char *error_str, size_t error_len) const 173{ 174 if (error_str) 175 error_str[0] = '\0'; 176 177 if (m_master_fd < 0) 178 { 179 if (error_str) 180 ::snprintf (error_str, error_len, "%s", "master file descriptor is invalid"); 181 return NULL; 182 } 183 const char *slave_name = ::ptsname (m_master_fd); 184 185 if (error_str && slave_name == NULL) 186 ::strerror_r (errno, error_str, error_len); 187 188 return slave_name; 189} 190 191 192//---------------------------------------------------------------------- 193// Fork a child process and have its stdio routed to a pseudo terminal. 194// 195// In the parent process when a valid pid is returned, the master file 196// descriptor can be used as a read/write access to stdio of the 197// child process. 198// 199// In the child process the stdin/stdout/stderr will already be routed 200// to the slave pseudo terminal and the master file descriptor will be 201// closed as it is no longer needed by the child process. 202// 203// This class will close the file descriptors for the master/slave 204// when the destructor is called, so be sure to call 205// ReleaseMasterFileDescriptor() or ReleaseSlaveFileDescriptor() if any 206// file descriptors are going to be used past the lifespan of this 207// object. 208// 209// RETURNS: 210// in the parent process: the pid of the child, or -1 if fork fails 211// in the child process: zero 212//---------------------------------------------------------------------- 213lldb::pid_t 214PseudoTerminal::Fork (char *error_str, size_t error_len) 215{ 216 if (error_str) 217 error_str[0] = '\0'; 218 219 pid_t pid = LLDB_INVALID_PROCESS_ID; 220 if (OpenFirstAvailableMaster (O_RDWR, error_str, error_len)) 221 { 222 // Successfully opened our master pseudo terminal 223 224 pid = ::fork (); 225 if (pid < 0) 226 { 227 // Fork failed 228 if (error_str) 229 ::strerror_r (errno, error_str, error_len); 230 } 231 else if (pid == 0) 232 { 233 // Child Process 234 ::setsid(); 235 236 if (OpenSlave (O_RDWR, error_str, error_len)) 237 { 238 // Successfully opened slave 239 // We are done with the master in the child process so lets close it 240 CloseMasterFileDescriptor (); 241 242#if defined(TIOCSCTTY) 243 // Acquire the controlling terminal 244 if (::ioctl (m_slave_fd, TIOCSCTTY, (char *)0) < 0) 245 { 246 if (error_str) 247 ::strerror_r (errno, error_str, error_len); 248 } 249#endif 250 // Duplicate all stdio file descriptors to the slave pseudo terminal 251 if (::dup2 (m_slave_fd, STDIN_FILENO) != STDIN_FILENO) 252 { 253 if (error_str && !error_str[0]) 254 ::strerror_r (errno, error_str, error_len); 255 } 256 257 if (::dup2 (m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) 258 { 259 if (error_str && !error_str[0]) 260 ::strerror_r (errno, error_str, error_len); 261 } 262 263 if (::dup2 (m_slave_fd, STDERR_FILENO) != STDERR_FILENO) 264 { 265 if (error_str && !error_str[0]) 266 ::strerror_r (errno, error_str, error_len); 267 } 268 } 269 } 270 else 271 { 272 // Parent Process 273 // Do nothing and let the pid get returned! 274 } 275 } 276 return pid; 277} 278 279//---------------------------------------------------------------------- 280// The master file descriptor accessor. This object retains ownership 281// of the master file descriptor when this accessor is used. Use 282// ReleaseMasterFileDescriptor() if you wish this object to release 283// ownership of the master file descriptor. 284// 285// Returns the master file descriptor, or -1 if the master file 286// descriptor is not currently valid. 287//---------------------------------------------------------------------- 288int 289PseudoTerminal::GetMasterFileDescriptor () const 290{ 291 return m_master_fd; 292} 293 294//---------------------------------------------------------------------- 295// The slave file descriptor accessor. 296// 297// Returns the slave file descriptor, or -1 if the slave file 298// descriptor is not currently valid. 299//---------------------------------------------------------------------- 300int 301PseudoTerminal::GetSlaveFileDescriptor () const 302{ 303 return m_slave_fd; 304} 305 306//---------------------------------------------------------------------- 307// Release ownership of the master pseudo terminal file descriptor 308// without closing it. The destructor for this class will close the 309// master file descriptor if the ownership isn't released using this 310// call and the master file descriptor has been opened. 311//---------------------------------------------------------------------- 312int 313PseudoTerminal::ReleaseMasterFileDescriptor () 314{ 315 // Release ownership of the master pseudo terminal file 316 // descriptor without closing it. (the destructor for this 317 // class will close it otherwise!) 318 int fd = m_master_fd; 319 m_master_fd = invalid_fd; 320 return fd; 321} 322 323//---------------------------------------------------------------------- 324// Release ownership of the slave pseudo terminal file descriptor 325// without closing it. The destructor for this class will close the 326// slave file descriptor if the ownership isn't released using this 327// call and the slave file descriptor has been opened. 328//---------------------------------------------------------------------- 329int 330PseudoTerminal::ReleaseSlaveFileDescriptor () 331{ 332 // Release ownership of the slave pseudo terminal file 333 // descriptor without closing it (the destructor for this 334 // class will close it otherwise!) 335 int fd = m_slave_fd; 336 m_slave_fd = invalid_fd; 337 return fd; 338} 339 340