1 //===-- PseudoTerminal.cpp ------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Host/PseudoTerminal.h" 10 #include "lldb/Host/Config.h" 11 #include "llvm/Support/Errc.h" 12 #include "llvm/Support/Errno.h" 13 #include <cassert> 14 #include <limits.h> 15 #include <mutex> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #if defined(TIOCSCTTY) 20 #include <sys/ioctl.h> 21 #endif 22 23 #include "lldb/Host/PosixApi.h" 24 25 #if defined(__ANDROID__) 26 int posix_openpt(int flags); 27 #endif 28 29 using namespace lldb_private; 30 31 // Write string describing error number 32 static void ErrnoToStr(char *error_str, size_t error_len) { 33 std::string strerror = llvm::sys::StrError(); 34 ::snprintf(error_str, error_len, "%s", strerror.c_str()); 35 } 36 37 // PseudoTerminal constructor 38 PseudoTerminal::PseudoTerminal() 39 : m_primary_fd(invalid_fd), m_secondary_fd(invalid_fd) {} 40 41 // Destructor 42 // 43 // The destructor will close the primary and secondary file descriptors if they 44 // are valid and ownership has not been released using the 45 // ReleasePrimaryFileDescriptor() or the ReleaseSaveFileDescriptor() member 46 // functions. 47 PseudoTerminal::~PseudoTerminal() { 48 ClosePrimaryFileDescriptor(); 49 CloseSecondaryFileDescriptor(); 50 } 51 52 // Close the primary file descriptor if it is valid. 53 void PseudoTerminal::ClosePrimaryFileDescriptor() { 54 if (m_primary_fd >= 0) { 55 ::close(m_primary_fd); 56 m_primary_fd = invalid_fd; 57 } 58 } 59 60 // Close the secondary file descriptor if it is valid. 61 void PseudoTerminal::CloseSecondaryFileDescriptor() { 62 if (m_secondary_fd >= 0) { 63 ::close(m_secondary_fd); 64 m_secondary_fd = invalid_fd; 65 } 66 } 67 68 llvm::Error PseudoTerminal::OpenFirstAvailablePrimary(int oflag) { 69 #if LLDB_ENABLE_POSIX 70 // Open the primary side of a pseudo terminal 71 m_primary_fd = ::posix_openpt(oflag); 72 if (m_primary_fd < 0) { 73 return llvm::errorCodeToError( 74 std::error_code(errno, std::generic_category())); 75 } 76 77 // Grant access to the secondary pseudo terminal 78 if (::grantpt(m_primary_fd) < 0) { 79 std::error_code EC(errno, std::generic_category()); 80 ClosePrimaryFileDescriptor(); 81 return llvm::errorCodeToError(EC); 82 } 83 84 // Clear the lock flag on the secondary pseudo terminal 85 if (::unlockpt(m_primary_fd) < 0) { 86 std::error_code EC(errno, std::generic_category()); 87 ClosePrimaryFileDescriptor(); 88 return llvm::errorCodeToError(EC); 89 } 90 91 return llvm::Error::success(); 92 #else 93 return llvm::errorCodeToError(llvm::errc::not_supported); 94 #endif 95 } 96 97 llvm::Error PseudoTerminal::OpenSecondary(int oflag) { 98 CloseSecondaryFileDescriptor(); 99 100 std::string name = GetSecondaryName(); 101 m_secondary_fd = llvm::sys::RetryAfterSignal(-1, ::open, name.c_str(), oflag); 102 if (m_secondary_fd >= 0) 103 return llvm::Error::success(); 104 105 return llvm::errorCodeToError( 106 std::error_code(errno, std::generic_category())); 107 } 108 109 std::string PseudoTerminal::GetSecondaryName() const { 110 assert(m_primary_fd >= 0); 111 #if HAVE_PTSNAME_R 112 char buf[PATH_MAX]; 113 buf[0] = '\0'; 114 int r = ptsname_r(m_primary_fd, buf, sizeof(buf)); 115 assert(r == 0); 116 return buf; 117 #else 118 static std::mutex mutex; 119 std::lock_guard<std::mutex> guard(mutex); 120 const char *r = ptsname(m_primary_fd); 121 assert(r != nullptr); 122 return r; 123 #endif 124 } 125 126 // Fork a child process and have its stdio routed to a pseudo terminal. 127 // 128 // In the parent process when a valid pid is returned, the primary file 129 // descriptor can be used as a read/write access to stdio of the child process. 130 // 131 // In the child process the stdin/stdout/stderr will already be routed to the 132 // secondary pseudo terminal and the primary file descriptor will be closed as 133 // it is no longer needed by the child process. 134 // 135 // This class will close the file descriptors for the primary/secondary when the 136 // destructor is called, so be sure to call ReleasePrimaryFileDescriptor() or 137 // ReleaseSecondaryFileDescriptor() if any file descriptors are going to be used 138 // past the lifespan of this object. 139 // 140 // RETURNS: 141 // in the parent process: the pid of the child, or -1 if fork fails 142 // in the child process: zero 143 lldb::pid_t PseudoTerminal::Fork(char *error_str, size_t error_len) { 144 if (error_str) 145 error_str[0] = '\0'; 146 pid_t pid = LLDB_INVALID_PROCESS_ID; 147 #if LLDB_ENABLE_POSIX 148 if (llvm::Error Err = OpenFirstAvailablePrimary(O_RDWR | O_CLOEXEC)) { 149 snprintf(error_str, error_len, "%s", toString(std::move(Err)).c_str()); 150 return LLDB_INVALID_PROCESS_ID; 151 } 152 153 pid = ::fork(); 154 if (pid < 0) { 155 // Fork failed 156 if (error_str) 157 ErrnoToStr(error_str, error_len); 158 } else if (pid == 0) { 159 // Child Process 160 ::setsid(); 161 162 if (llvm::Error Err = OpenSecondary(O_RDWR)) { 163 snprintf(error_str, error_len, "%s", toString(std::move(Err)).c_str()); 164 return LLDB_INVALID_PROCESS_ID; 165 } 166 167 // Primary FD should have O_CLOEXEC set, but let's close it just in 168 // case... 169 ClosePrimaryFileDescriptor(); 170 171 #if defined(TIOCSCTTY) 172 // Acquire the controlling terminal 173 if (::ioctl(m_secondary_fd, TIOCSCTTY, (char *)0) < 0) { 174 if (error_str) 175 ErrnoToStr(error_str, error_len); 176 } 177 #endif 178 // Duplicate all stdio file descriptors to the secondary pseudo terminal 179 if (::dup2(m_secondary_fd, STDIN_FILENO) != STDIN_FILENO) { 180 if (error_str && !error_str[0]) 181 ErrnoToStr(error_str, error_len); 182 } 183 184 if (::dup2(m_secondary_fd, STDOUT_FILENO) != STDOUT_FILENO) { 185 if (error_str && !error_str[0]) 186 ErrnoToStr(error_str, error_len); 187 } 188 189 if (::dup2(m_secondary_fd, STDERR_FILENO) != STDERR_FILENO) { 190 if (error_str && !error_str[0]) 191 ErrnoToStr(error_str, error_len); 192 } 193 } else { 194 // Parent Process 195 // Do nothing and let the pid get returned! 196 } 197 #endif 198 return pid; 199 } 200 201 // The primary file descriptor accessor. This object retains ownership of the 202 // primary file descriptor when this accessor is used. Use 203 // ReleasePrimaryFileDescriptor() if you wish this object to release ownership 204 // of the primary file descriptor. 205 // 206 // Returns the primary file descriptor, or -1 if the primary file descriptor is 207 // not currently valid. 208 int PseudoTerminal::GetPrimaryFileDescriptor() const { return m_primary_fd; } 209 210 // The secondary file descriptor accessor. 211 // 212 // Returns the secondary file descriptor, or -1 if the secondary file descriptor 213 // is not currently valid. 214 int PseudoTerminal::GetSecondaryFileDescriptor() const { 215 return m_secondary_fd; 216 } 217 218 // Release ownership of the primary pseudo terminal file descriptor without 219 // closing it. The destructor for this class will close the primary file 220 // descriptor if the ownership isn't released using this call and the primary 221 // file descriptor has been opened. 222 int PseudoTerminal::ReleasePrimaryFileDescriptor() { 223 // Release ownership of the primary pseudo terminal file descriptor without 224 // closing it. (the destructor for this class will close it otherwise!) 225 int fd = m_primary_fd; 226 m_primary_fd = invalid_fd; 227 return fd; 228 } 229 230 // Release ownership of the secondary pseudo terminal file descriptor without 231 // closing it. The destructor for this class will close the secondary file 232 // descriptor if the ownership isn't released using this call and the secondary 233 // file descriptor has been opened. 234 int PseudoTerminal::ReleaseSecondaryFileDescriptor() { 235 // Release ownership of the secondary pseudo terminal file descriptor without 236 // closing it (the destructor for this class will close it otherwise!) 237 int fd = m_secondary_fd; 238 m_secondary_fd = invalid_fd; 239 return fd; 240 } 241