PseudoTerminal.cpp revision 344779
1317027Sdim//===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===// 2317027Sdim// 3317027Sdim// The LLVM Compiler Infrastructure 4317027Sdim// 5317027Sdim// This file is distributed under the University of Illinois Open Source 6317027Sdim// License. See LICENSE.TXT for details. 7317027Sdim// 8317027Sdim//===----------------------------------------------------------------------===// 9317027Sdim 10317027Sdim#include "lldb/Host/PseudoTerminal.h" 11317027Sdim#include "lldb/Host/Config.h" 12317027Sdim 13344779Sdim#include "llvm/Support/Errno.h" 14344779Sdim 15317027Sdim#include <stdio.h> 16317027Sdim#include <stdlib.h> 17317027Sdim#include <string.h> 18317027Sdim#if defined(TIOCSCTTY) 19317027Sdim#include <sys/ioctl.h> 20317027Sdim#endif 21317027Sdim 22317027Sdim#include "lldb/Host/PosixApi.h" 23317027Sdim 24317027Sdim#if defined(__ANDROID__) 25317027Sdimint posix_openpt(int flags); 26317027Sdim#endif 27317027Sdim 28327952Sdimusing namespace lldb_private; 29317027Sdim 30317027Sdim//---------------------------------------------------------------------- 31344779Sdim// Write string describing error number 32344779Sdim//---------------------------------------------------------------------- 33344779Sdimstatic void ErrnoToStr(char *error_str, size_t error_len) { 34344779Sdim std::string strerror = llvm::sys::StrError(); 35344779Sdim ::snprintf(error_str, error_len, "%s", strerror.c_str()); 36344779Sdim} 37344779Sdim 38344779Sdim//---------------------------------------------------------------------- 39317027Sdim// PseudoTerminal constructor 40317027Sdim//---------------------------------------------------------------------- 41317027SdimPseudoTerminal::PseudoTerminal() 42317027Sdim : m_master_fd(invalid_fd), m_slave_fd(invalid_fd) {} 43317027Sdim 44317027Sdim//---------------------------------------------------------------------- 45317027Sdim// Destructor 46317027Sdim// 47341825Sdim// The destructor will close the master and slave file descriptors if they are 48341825Sdim// valid and ownership has not been released using the 49341825Sdim// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor() member 50341825Sdim// functions. 51317027Sdim//---------------------------------------------------------------------- 52317027SdimPseudoTerminal::~PseudoTerminal() { 53317027Sdim CloseMasterFileDescriptor(); 54317027Sdim CloseSlaveFileDescriptor(); 55317027Sdim} 56317027Sdim 57317027Sdim//---------------------------------------------------------------------- 58317027Sdim// Close the master file descriptor if it is valid. 59317027Sdim//---------------------------------------------------------------------- 60317027Sdimvoid PseudoTerminal::CloseMasterFileDescriptor() { 61317027Sdim if (m_master_fd >= 0) { 62317027Sdim ::close(m_master_fd); 63317027Sdim m_master_fd = invalid_fd; 64317027Sdim } 65317027Sdim} 66317027Sdim 67317027Sdim//---------------------------------------------------------------------- 68317027Sdim// Close the slave file descriptor if it is valid. 69317027Sdim//---------------------------------------------------------------------- 70317027Sdimvoid PseudoTerminal::CloseSlaveFileDescriptor() { 71317027Sdim if (m_slave_fd >= 0) { 72317027Sdim ::close(m_slave_fd); 73317027Sdim m_slave_fd = invalid_fd; 74317027Sdim } 75317027Sdim} 76317027Sdim 77317027Sdim//---------------------------------------------------------------------- 78341825Sdim// Open the first available pseudo terminal with OFLAG as the permissions. The 79341825Sdim// file descriptor is stored in this object and can be accessed with the 80341825Sdim// MasterFileDescriptor() accessor. The ownership of the master file descriptor 81341825Sdim// can be released using the ReleaseMasterFileDescriptor() accessor. If this 82341825Sdim// object has a valid master files descriptor when its destructor is called, it 83341825Sdim// will close the master file descriptor, therefore clients must call 84341825Sdim// ReleaseMasterFileDescriptor() if they wish to use the master file descriptor 85341825Sdim// after this object is out of scope or destroyed. 86317027Sdim// 87317027Sdim// RETURNS: 88317027Sdim// True when successful, false indicating an error occurred. 89317027Sdim//---------------------------------------------------------------------- 90317027Sdimbool PseudoTerminal::OpenFirstAvailableMaster(int oflag, char *error_str, 91317027Sdim size_t error_len) { 92317027Sdim if (error_str) 93317027Sdim error_str[0] = '\0'; 94317027Sdim 95317027Sdim#if !defined(LLDB_DISABLE_POSIX) 96317027Sdim // Open the master side of a pseudo terminal 97317027Sdim m_master_fd = ::posix_openpt(oflag); 98317027Sdim if (m_master_fd < 0) { 99317027Sdim if (error_str) 100344779Sdim ErrnoToStr(error_str, error_len); 101317027Sdim return false; 102317027Sdim } 103317027Sdim 104317027Sdim // Grant access to the slave pseudo terminal 105317027Sdim if (::grantpt(m_master_fd) < 0) { 106317027Sdim if (error_str) 107344779Sdim ErrnoToStr(error_str, error_len); 108317027Sdim CloseMasterFileDescriptor(); 109317027Sdim return false; 110317027Sdim } 111317027Sdim 112317027Sdim // Clear the lock flag on the slave pseudo terminal 113317027Sdim if (::unlockpt(m_master_fd) < 0) { 114317027Sdim if (error_str) 115344779Sdim ErrnoToStr(error_str, error_len); 116317027Sdim CloseMasterFileDescriptor(); 117317027Sdim return false; 118317027Sdim } 119317027Sdim 120317027Sdim return true; 121317027Sdim#else 122317027Sdim if (error_str) 123317027Sdim ::snprintf(error_str, error_len, "%s", "pseudo terminal not supported"); 124317027Sdim return false; 125317027Sdim#endif 126317027Sdim} 127317027Sdim 128317027Sdim//---------------------------------------------------------------------- 129341825Sdim// Open the slave pseudo terminal for the current master pseudo terminal. A 130341825Sdim// master pseudo terminal should already be valid prior to calling this 131341825Sdim// function (see OpenFirstAvailableMaster()). The file descriptor is stored 132341825Sdim// this object's member variables and can be accessed via the 133341825Sdim// GetSlaveFileDescriptor(), or released using the ReleaseSlaveFileDescriptor() 134341825Sdim// member function. 135317027Sdim// 136317027Sdim// RETURNS: 137317027Sdim// True when successful, false indicating an error occurred. 138317027Sdim//---------------------------------------------------------------------- 139317027Sdimbool PseudoTerminal::OpenSlave(int oflag, char *error_str, size_t error_len) { 140317027Sdim if (error_str) 141317027Sdim error_str[0] = '\0'; 142317027Sdim 143317027Sdim CloseSlaveFileDescriptor(); 144317027Sdim 145317027Sdim // Open the master side of a pseudo terminal 146317027Sdim const char *slave_name = GetSlaveName(error_str, error_len); 147317027Sdim 148317027Sdim if (slave_name == nullptr) 149317027Sdim return false; 150317027Sdim 151317027Sdim m_slave_fd = ::open(slave_name, oflag); 152317027Sdim 153317027Sdim if (m_slave_fd < 0) { 154317027Sdim if (error_str) 155344779Sdim ErrnoToStr(error_str, error_len); 156317027Sdim return false; 157317027Sdim } 158317027Sdim 159317027Sdim return true; 160317027Sdim} 161317027Sdim 162317027Sdim//---------------------------------------------------------------------- 163341825Sdim// Get the name of the slave pseudo terminal. A master pseudo terminal should 164341825Sdim// already be valid prior to calling this function (see 165317027Sdim// OpenFirstAvailableMaster()). 166317027Sdim// 167317027Sdim// RETURNS: 168317027Sdim// NULL if no valid master pseudo terminal or if ptsname() fails. 169317027Sdim// The name of the slave pseudo terminal as a NULL terminated C string 170317027Sdim// that comes from static memory, so a copy of the string should be 171317027Sdim// made as subsequent calls can change this value. 172317027Sdim//---------------------------------------------------------------------- 173317027Sdimconst char *PseudoTerminal::GetSlaveName(char *error_str, 174317027Sdim size_t error_len) const { 175317027Sdim if (error_str) 176317027Sdim error_str[0] = '\0'; 177317027Sdim 178317027Sdim if (m_master_fd < 0) { 179317027Sdim if (error_str) 180317027Sdim ::snprintf(error_str, error_len, "%s", 181317027Sdim "master file descriptor is invalid"); 182317027Sdim return nullptr; 183317027Sdim } 184317027Sdim const char *slave_name = ::ptsname(m_master_fd); 185317027Sdim 186317027Sdim if (error_str && slave_name == nullptr) 187344779Sdim ErrnoToStr(error_str, error_len); 188317027Sdim 189317027Sdim return slave_name; 190317027Sdim} 191317027Sdim 192317027Sdim//---------------------------------------------------------------------- 193317027Sdim// Fork a child process and have its stdio routed to a pseudo terminal. 194317027Sdim// 195317027Sdim// In the parent process when a valid pid is returned, the master file 196341825Sdim// descriptor can be used as a read/write access to stdio of the child process. 197317027Sdim// 198341825Sdim// In the child process the stdin/stdout/stderr will already be routed to the 199341825Sdim// slave pseudo terminal and the master file descriptor will be closed as it is 200341825Sdim// no longer needed by the child process. 201317027Sdim// 202341825Sdim// This class will close the file descriptors for the master/slave when the 203341825Sdim// destructor is called, so be sure to call ReleaseMasterFileDescriptor() or 204341825Sdim// ReleaseSlaveFileDescriptor() if any file descriptors are going to be used 205341825Sdim// past the lifespan of this object. 206317027Sdim// 207317027Sdim// RETURNS: 208317027Sdim// in the parent process: the pid of the child, or -1 if fork fails 209317027Sdim// in the child process: zero 210317027Sdim//---------------------------------------------------------------------- 211317027Sdimlldb::pid_t PseudoTerminal::Fork(char *error_str, size_t error_len) { 212317027Sdim if (error_str) 213317027Sdim error_str[0] = '\0'; 214317027Sdim pid_t pid = LLDB_INVALID_PROCESS_ID; 215317027Sdim#if !defined(LLDB_DISABLE_POSIX) 216317027Sdim int flags = O_RDWR; 217317027Sdim flags |= O_CLOEXEC; 218317027Sdim if (OpenFirstAvailableMaster(flags, error_str, error_len)) { 219317027Sdim // Successfully opened our master pseudo terminal 220317027Sdim 221317027Sdim pid = ::fork(); 222317027Sdim if (pid < 0) { 223317027Sdim // Fork failed 224317027Sdim if (error_str) 225344779Sdim ErrnoToStr(error_str, error_len); 226317027Sdim } else if (pid == 0) { 227317027Sdim // Child Process 228317027Sdim ::setsid(); 229317027Sdim 230317027Sdim if (OpenSlave(O_RDWR, error_str, error_len)) { 231317027Sdim // Successfully opened slave 232317027Sdim 233317027Sdim // Master FD should have O_CLOEXEC set, but let's close it just in 234317027Sdim // case... 235317027Sdim CloseMasterFileDescriptor(); 236317027Sdim 237317027Sdim#if defined(TIOCSCTTY) 238317027Sdim // Acquire the controlling terminal 239317027Sdim if (::ioctl(m_slave_fd, TIOCSCTTY, (char *)0) < 0) { 240317027Sdim if (error_str) 241344779Sdim ErrnoToStr(error_str, error_len); 242317027Sdim } 243317027Sdim#endif 244317027Sdim // Duplicate all stdio file descriptors to the slave pseudo terminal 245317027Sdim if (::dup2(m_slave_fd, STDIN_FILENO) != STDIN_FILENO) { 246317027Sdim if (error_str && !error_str[0]) 247344779Sdim ErrnoToStr(error_str, error_len); 248317027Sdim } 249317027Sdim 250317027Sdim if (::dup2(m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) { 251317027Sdim if (error_str && !error_str[0]) 252344779Sdim ErrnoToStr(error_str, error_len); 253317027Sdim } 254317027Sdim 255317027Sdim if (::dup2(m_slave_fd, STDERR_FILENO) != STDERR_FILENO) { 256317027Sdim if (error_str && !error_str[0]) 257344779Sdim ErrnoToStr(error_str, error_len); 258317027Sdim } 259317027Sdim } 260317027Sdim } else { 261317027Sdim // Parent Process 262317027Sdim // Do nothing and let the pid get returned! 263317027Sdim } 264317027Sdim } 265317027Sdim#endif 266317027Sdim return pid; 267317027Sdim} 268317027Sdim 269317027Sdim//---------------------------------------------------------------------- 270341825Sdim// The master file descriptor accessor. This object retains ownership of the 271341825Sdim// master file descriptor when this accessor is used. Use 272341825Sdim// ReleaseMasterFileDescriptor() if you wish this object to release ownership 273341825Sdim// of the master file descriptor. 274317027Sdim// 275341825Sdim// Returns the master file descriptor, or -1 if the master file descriptor is 276341825Sdim// not currently valid. 277317027Sdim//---------------------------------------------------------------------- 278317027Sdimint PseudoTerminal::GetMasterFileDescriptor() const { return m_master_fd; } 279317027Sdim 280317027Sdim//---------------------------------------------------------------------- 281317027Sdim// The slave file descriptor accessor. 282317027Sdim// 283341825Sdim// Returns the slave file descriptor, or -1 if the slave file descriptor is not 284341825Sdim// currently valid. 285317027Sdim//---------------------------------------------------------------------- 286317027Sdimint PseudoTerminal::GetSlaveFileDescriptor() const { return m_slave_fd; } 287317027Sdim 288317027Sdim//---------------------------------------------------------------------- 289341825Sdim// Release ownership of the master pseudo terminal file descriptor without 290341825Sdim// closing it. The destructor for this class will close the master file 291341825Sdim// descriptor if the ownership isn't released using this call and the master 292341825Sdim// file descriptor has been opened. 293317027Sdim//---------------------------------------------------------------------- 294317027Sdimint PseudoTerminal::ReleaseMasterFileDescriptor() { 295341825Sdim // Release ownership of the master pseudo terminal file descriptor without 296341825Sdim // closing it. (the destructor for this class will close it otherwise!) 297317027Sdim int fd = m_master_fd; 298317027Sdim m_master_fd = invalid_fd; 299317027Sdim return fd; 300317027Sdim} 301317027Sdim 302317027Sdim//---------------------------------------------------------------------- 303341825Sdim// Release ownership of the slave pseudo terminal file descriptor without 304341825Sdim// closing it. The destructor for this class will close the slave file 305341825Sdim// descriptor if the ownership isn't released using this call and the slave 306341825Sdim// file descriptor has been opened. 307317027Sdim//---------------------------------------------------------------------- 308317027Sdimint PseudoTerminal::ReleaseSlaveFileDescriptor() { 309341825Sdim // Release ownership of the slave pseudo terminal file descriptor without 310341825Sdim // closing it (the destructor for this class will close it otherwise!) 311317027Sdim int fd = m_slave_fd; 312317027Sdim m_slave_fd = invalid_fd; 313317027Sdim return fd; 314317027Sdim} 315