1317027Sdim//===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===// 2317027Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6317027Sdim// 7317027Sdim//===----------------------------------------------------------------------===// 8317027Sdim 9317027Sdim#include "lldb/Host/PseudoTerminal.h" 10317027Sdim#include "lldb/Host/Config.h" 11317027Sdim 12344779Sdim#include "llvm/Support/Errno.h" 13344779Sdim 14317027Sdim#include <stdio.h> 15317027Sdim#include <stdlib.h> 16317027Sdim#include <string.h> 17317027Sdim#if defined(TIOCSCTTY) 18317027Sdim#include <sys/ioctl.h> 19317027Sdim#endif 20317027Sdim 21317027Sdim#include "lldb/Host/PosixApi.h" 22317027Sdim 23317027Sdim#if defined(__ANDROID__) 24317027Sdimint posix_openpt(int flags); 25317027Sdim#endif 26317027Sdim 27327952Sdimusing namespace lldb_private; 28317027Sdim 29344779Sdim// Write string describing error number 30344779Sdimstatic void ErrnoToStr(char *error_str, size_t error_len) { 31344779Sdim std::string strerror = llvm::sys::StrError(); 32344779Sdim ::snprintf(error_str, error_len, "%s", strerror.c_str()); 33344779Sdim} 34344779Sdim 35317027Sdim// PseudoTerminal constructor 36317027SdimPseudoTerminal::PseudoTerminal() 37317027Sdim : m_master_fd(invalid_fd), m_slave_fd(invalid_fd) {} 38317027Sdim 39317027Sdim// Destructor 40317027Sdim// 41341825Sdim// The destructor will close the master and slave file descriptors if they are 42341825Sdim// valid and ownership has not been released using the 43341825Sdim// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor() member 44341825Sdim// functions. 45317027SdimPseudoTerminal::~PseudoTerminal() { 46317027Sdim CloseMasterFileDescriptor(); 47317027Sdim CloseSlaveFileDescriptor(); 48317027Sdim} 49317027Sdim 50317027Sdim// Close the master file descriptor if it is valid. 51317027Sdimvoid PseudoTerminal::CloseMasterFileDescriptor() { 52317027Sdim if (m_master_fd >= 0) { 53317027Sdim ::close(m_master_fd); 54317027Sdim m_master_fd = invalid_fd; 55317027Sdim } 56317027Sdim} 57317027Sdim 58317027Sdim// Close the slave file descriptor if it is valid. 59317027Sdimvoid PseudoTerminal::CloseSlaveFileDescriptor() { 60317027Sdim if (m_slave_fd >= 0) { 61317027Sdim ::close(m_slave_fd); 62317027Sdim m_slave_fd = invalid_fd; 63317027Sdim } 64317027Sdim} 65317027Sdim 66341825Sdim// Open the first available pseudo terminal with OFLAG as the permissions. The 67341825Sdim// file descriptor is stored in this object and can be accessed with the 68341825Sdim// MasterFileDescriptor() accessor. The ownership of the master file descriptor 69341825Sdim// can be released using the ReleaseMasterFileDescriptor() accessor. If this 70341825Sdim// object has a valid master files descriptor when its destructor is called, it 71341825Sdim// will close the master file descriptor, therefore clients must call 72341825Sdim// ReleaseMasterFileDescriptor() if they wish to use the master file descriptor 73341825Sdim// after this object is out of scope or destroyed. 74317027Sdim// 75317027Sdim// RETURNS: 76317027Sdim// True when successful, false indicating an error occurred. 77317027Sdimbool PseudoTerminal::OpenFirstAvailableMaster(int oflag, char *error_str, 78317027Sdim size_t error_len) { 79317027Sdim if (error_str) 80317027Sdim error_str[0] = '\0'; 81317027Sdim 82360784Sdim#if LLDB_ENABLE_POSIX 83317027Sdim // Open the master side of a pseudo terminal 84317027Sdim m_master_fd = ::posix_openpt(oflag); 85317027Sdim if (m_master_fd < 0) { 86317027Sdim if (error_str) 87344779Sdim ErrnoToStr(error_str, error_len); 88317027Sdim return false; 89317027Sdim } 90317027Sdim 91317027Sdim // Grant access to the slave pseudo terminal 92317027Sdim if (::grantpt(m_master_fd) < 0) { 93317027Sdim if (error_str) 94344779Sdim ErrnoToStr(error_str, error_len); 95317027Sdim CloseMasterFileDescriptor(); 96317027Sdim return false; 97317027Sdim } 98317027Sdim 99317027Sdim // Clear the lock flag on the slave pseudo terminal 100317027Sdim if (::unlockpt(m_master_fd) < 0) { 101317027Sdim if (error_str) 102344779Sdim ErrnoToStr(error_str, error_len); 103317027Sdim CloseMasterFileDescriptor(); 104317027Sdim return false; 105317027Sdim } 106317027Sdim 107317027Sdim return true; 108317027Sdim#else 109317027Sdim if (error_str) 110317027Sdim ::snprintf(error_str, error_len, "%s", "pseudo terminal not supported"); 111317027Sdim return false; 112317027Sdim#endif 113317027Sdim} 114317027Sdim 115341825Sdim// Open the slave pseudo terminal for the current master pseudo terminal. A 116341825Sdim// master pseudo terminal should already be valid prior to calling this 117341825Sdim// function (see OpenFirstAvailableMaster()). The file descriptor is stored 118341825Sdim// this object's member variables and can be accessed via the 119341825Sdim// GetSlaveFileDescriptor(), or released using the ReleaseSlaveFileDescriptor() 120341825Sdim// member function. 121317027Sdim// 122317027Sdim// RETURNS: 123317027Sdim// True when successful, false indicating an error occurred. 124317027Sdimbool PseudoTerminal::OpenSlave(int oflag, char *error_str, size_t error_len) { 125317027Sdim if (error_str) 126317027Sdim error_str[0] = '\0'; 127317027Sdim 128317027Sdim CloseSlaveFileDescriptor(); 129317027Sdim 130317027Sdim // Open the master side of a pseudo terminal 131317027Sdim const char *slave_name = GetSlaveName(error_str, error_len); 132317027Sdim 133317027Sdim if (slave_name == nullptr) 134317027Sdim return false; 135317027Sdim 136353358Sdim m_slave_fd = llvm::sys::RetryAfterSignal(-1, ::open, slave_name, oflag); 137317027Sdim 138317027Sdim if (m_slave_fd < 0) { 139317027Sdim if (error_str) 140344779Sdim ErrnoToStr(error_str, error_len); 141317027Sdim return false; 142317027Sdim } 143317027Sdim 144317027Sdim return true; 145317027Sdim} 146317027Sdim 147341825Sdim// Get the name of the slave pseudo terminal. A master pseudo terminal should 148341825Sdim// already be valid prior to calling this function (see 149317027Sdim// OpenFirstAvailableMaster()). 150317027Sdim// 151317027Sdim// RETURNS: 152317027Sdim// NULL if no valid master pseudo terminal or if ptsname() fails. 153317027Sdim// The name of the slave pseudo terminal as a NULL terminated C string 154317027Sdim// that comes from static memory, so a copy of the string should be 155317027Sdim// made as subsequent calls can change this value. 156317027Sdimconst char *PseudoTerminal::GetSlaveName(char *error_str, 157317027Sdim size_t error_len) const { 158317027Sdim if (error_str) 159317027Sdim error_str[0] = '\0'; 160317027Sdim 161317027Sdim if (m_master_fd < 0) { 162317027Sdim if (error_str) 163317027Sdim ::snprintf(error_str, error_len, "%s", 164317027Sdim "master file descriptor is invalid"); 165317027Sdim return nullptr; 166317027Sdim } 167317027Sdim const char *slave_name = ::ptsname(m_master_fd); 168317027Sdim 169317027Sdim if (error_str && slave_name == nullptr) 170344779Sdim ErrnoToStr(error_str, error_len); 171317027Sdim 172317027Sdim return slave_name; 173317027Sdim} 174317027Sdim 175317027Sdim// Fork a child process and have its stdio routed to a pseudo terminal. 176317027Sdim// 177317027Sdim// In the parent process when a valid pid is returned, the master file 178341825Sdim// descriptor can be used as a read/write access to stdio of the child process. 179317027Sdim// 180341825Sdim// In the child process the stdin/stdout/stderr will already be routed to the 181341825Sdim// slave pseudo terminal and the master file descriptor will be closed as it is 182341825Sdim// no longer needed by the child process. 183317027Sdim// 184341825Sdim// This class will close the file descriptors for the master/slave when the 185341825Sdim// destructor is called, so be sure to call ReleaseMasterFileDescriptor() or 186341825Sdim// ReleaseSlaveFileDescriptor() if any file descriptors are going to be used 187341825Sdim// past the lifespan of this object. 188317027Sdim// 189317027Sdim// RETURNS: 190317027Sdim// in the parent process: the pid of the child, or -1 if fork fails 191317027Sdim// in the child process: zero 192317027Sdimlldb::pid_t PseudoTerminal::Fork(char *error_str, size_t error_len) { 193317027Sdim if (error_str) 194317027Sdim error_str[0] = '\0'; 195317027Sdim pid_t pid = LLDB_INVALID_PROCESS_ID; 196360784Sdim#if LLDB_ENABLE_POSIX 197317027Sdim int flags = O_RDWR; 198317027Sdim flags |= O_CLOEXEC; 199317027Sdim if (OpenFirstAvailableMaster(flags, error_str, error_len)) { 200317027Sdim // Successfully opened our master pseudo terminal 201317027Sdim 202317027Sdim pid = ::fork(); 203317027Sdim if (pid < 0) { 204317027Sdim // Fork failed 205317027Sdim if (error_str) 206344779Sdim ErrnoToStr(error_str, error_len); 207317027Sdim } else if (pid == 0) { 208317027Sdim // Child Process 209317027Sdim ::setsid(); 210317027Sdim 211317027Sdim if (OpenSlave(O_RDWR, error_str, error_len)) { 212317027Sdim // Successfully opened slave 213317027Sdim 214317027Sdim // Master FD should have O_CLOEXEC set, but let's close it just in 215317027Sdim // case... 216317027Sdim CloseMasterFileDescriptor(); 217317027Sdim 218317027Sdim#if defined(TIOCSCTTY) 219317027Sdim // Acquire the controlling terminal 220317027Sdim if (::ioctl(m_slave_fd, TIOCSCTTY, (char *)0) < 0) { 221317027Sdim if (error_str) 222344779Sdim ErrnoToStr(error_str, error_len); 223317027Sdim } 224317027Sdim#endif 225317027Sdim // Duplicate all stdio file descriptors to the slave pseudo terminal 226317027Sdim if (::dup2(m_slave_fd, STDIN_FILENO) != STDIN_FILENO) { 227317027Sdim if (error_str && !error_str[0]) 228344779Sdim ErrnoToStr(error_str, error_len); 229317027Sdim } 230317027Sdim 231317027Sdim if (::dup2(m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) { 232317027Sdim if (error_str && !error_str[0]) 233344779Sdim ErrnoToStr(error_str, error_len); 234317027Sdim } 235317027Sdim 236317027Sdim if (::dup2(m_slave_fd, STDERR_FILENO) != STDERR_FILENO) { 237317027Sdim if (error_str && !error_str[0]) 238344779Sdim ErrnoToStr(error_str, error_len); 239317027Sdim } 240317027Sdim } 241317027Sdim } else { 242317027Sdim // Parent Process 243317027Sdim // Do nothing and let the pid get returned! 244317027Sdim } 245317027Sdim } 246317027Sdim#endif 247317027Sdim return pid; 248317027Sdim} 249317027Sdim 250341825Sdim// The master file descriptor accessor. This object retains ownership of the 251341825Sdim// master file descriptor when this accessor is used. Use 252341825Sdim// ReleaseMasterFileDescriptor() if you wish this object to release ownership 253341825Sdim// of the master file descriptor. 254317027Sdim// 255341825Sdim// Returns the master file descriptor, or -1 if the master file descriptor is 256341825Sdim// not currently valid. 257317027Sdimint PseudoTerminal::GetMasterFileDescriptor() const { return m_master_fd; } 258317027Sdim 259317027Sdim// The slave file descriptor accessor. 260317027Sdim// 261341825Sdim// Returns the slave file descriptor, or -1 if the slave file descriptor is not 262341825Sdim// currently valid. 263317027Sdimint PseudoTerminal::GetSlaveFileDescriptor() const { return m_slave_fd; } 264317027Sdim 265341825Sdim// Release ownership of the master pseudo terminal file descriptor without 266341825Sdim// closing it. The destructor for this class will close the master file 267341825Sdim// descriptor if the ownership isn't released using this call and the master 268341825Sdim// file descriptor has been opened. 269317027Sdimint PseudoTerminal::ReleaseMasterFileDescriptor() { 270341825Sdim // Release ownership of the master pseudo terminal file descriptor without 271341825Sdim // closing it. (the destructor for this class will close it otherwise!) 272317027Sdim int fd = m_master_fd; 273317027Sdim m_master_fd = invalid_fd; 274317027Sdim return fd; 275317027Sdim} 276317027Sdim 277341825Sdim// Release ownership of the slave pseudo terminal file descriptor without 278341825Sdim// closing it. The destructor for this class will close the slave file 279341825Sdim// descriptor if the ownership isn't released using this call and the slave 280341825Sdim// file descriptor has been opened. 281317027Sdimint PseudoTerminal::ReleaseSlaveFileDescriptor() { 282341825Sdim // Release ownership of the slave pseudo terminal file descriptor without 283341825Sdim // closing it (the destructor for this class will close it otherwise!) 284317027Sdim int fd = m_slave_fd; 285317027Sdim m_slave_fd = invalid_fd; 286317027Sdim return fd; 287317027Sdim} 288