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 // Open the secondary pseudo terminal for the current primary pseudo terminal. A 98 // primary pseudo terminal should already be valid prior to calling this 99 // function (see OpenFirstAvailablePrimary()). The file descriptor is stored 100 // this object's member variables and can be accessed via the 101 // GetSecondaryFileDescriptor(), or released using the 102 // ReleaseSecondaryFileDescriptor() member function. 103 // 104 // RETURNS: 105 // True when successful, false indicating an error occurred. 106 bool PseudoTerminal::OpenSecondary(int oflag, char *error_str, 107 size_t error_len) { 108 if (error_str) 109 error_str[0] = '\0'; 110 111 CloseSecondaryFileDescriptor(); 112 113 std::string name = GetSecondaryName(); 114 m_secondary_fd = llvm::sys::RetryAfterSignal(-1, ::open, name.c_str(), oflag); 115 if (m_secondary_fd < 0) { 116 if (error_str) 117 ErrnoToStr(error_str, error_len); 118 return false; 119 } 120 121 return true; 122 } 123 124 std::string PseudoTerminal::GetSecondaryName() const { 125 assert(m_primary_fd >= 0); 126 #if HAVE_PTSNAME_R 127 char buf[PATH_MAX]; 128 buf[0] = '\0'; 129 int r = ptsname_r(m_primary_fd, buf, sizeof(buf)); 130 assert(r == 0); 131 return buf; 132 #else 133 static std::mutex mutex; 134 std::lock_guard<std::mutex> guard(mutex); 135 const char *r = ptsname(m_primary_fd); 136 assert(r != nullptr); 137 return r; 138 #endif 139 } 140 141 // Fork a child process and have its stdio routed to a pseudo terminal. 142 // 143 // In the parent process when a valid pid is returned, the primary file 144 // descriptor can be used as a read/write access to stdio of the child process. 145 // 146 // In the child process the stdin/stdout/stderr will already be routed to the 147 // secondary pseudo terminal and the primary file descriptor will be closed as 148 // it is no longer needed by the child process. 149 // 150 // This class will close the file descriptors for the primary/secondary when the 151 // destructor is called, so be sure to call ReleasePrimaryFileDescriptor() or 152 // ReleaseSecondaryFileDescriptor() if any file descriptors are going to be used 153 // past the lifespan of this object. 154 // 155 // RETURNS: 156 // in the parent process: the pid of the child, or -1 if fork fails 157 // in the child process: zero 158 lldb::pid_t PseudoTerminal::Fork(char *error_str, size_t error_len) { 159 if (error_str) 160 error_str[0] = '\0'; 161 pid_t pid = LLDB_INVALID_PROCESS_ID; 162 #if LLDB_ENABLE_POSIX 163 if (llvm::Error Err = OpenFirstAvailablePrimary(O_RDWR | O_CLOEXEC)) { 164 snprintf(error_str, error_len, "%s", toString(std::move(Err)).c_str()); 165 return LLDB_INVALID_PROCESS_ID; 166 } 167 168 pid = ::fork(); 169 if (pid < 0) { 170 // Fork failed 171 if (error_str) 172 ErrnoToStr(error_str, error_len); 173 } else if (pid == 0) { 174 // Child Process 175 ::setsid(); 176 177 if (OpenSecondary(O_RDWR, error_str, error_len)) { 178 // Successfully opened secondary 179 180 // Primary FD should have O_CLOEXEC set, but let's close it just in 181 // case... 182 ClosePrimaryFileDescriptor(); 183 184 #if defined(TIOCSCTTY) 185 // Acquire the controlling terminal 186 if (::ioctl(m_secondary_fd, TIOCSCTTY, (char *)0) < 0) { 187 if (error_str) 188 ErrnoToStr(error_str, error_len); 189 } 190 #endif 191 // Duplicate all stdio file descriptors to the secondary pseudo terminal 192 if (::dup2(m_secondary_fd, STDIN_FILENO) != STDIN_FILENO) { 193 if (error_str && !error_str[0]) 194 ErrnoToStr(error_str, error_len); 195 } 196 197 if (::dup2(m_secondary_fd, STDOUT_FILENO) != STDOUT_FILENO) { 198 if (error_str && !error_str[0]) 199 ErrnoToStr(error_str, error_len); 200 } 201 202 if (::dup2(m_secondary_fd, STDERR_FILENO) != STDERR_FILENO) { 203 if (error_str && !error_str[0]) 204 ErrnoToStr(error_str, error_len); 205 } 206 } 207 } else { 208 // Parent Process 209 // Do nothing and let the pid get returned! 210 } 211 #endif 212 return pid; 213 } 214 215 // The primary file descriptor accessor. This object retains ownership of the 216 // primary file descriptor when this accessor is used. Use 217 // ReleasePrimaryFileDescriptor() if you wish this object to release ownership 218 // of the primary file descriptor. 219 // 220 // Returns the primary file descriptor, or -1 if the primary file descriptor is 221 // not currently valid. 222 int PseudoTerminal::GetPrimaryFileDescriptor() const { return m_primary_fd; } 223 224 // The secondary file descriptor accessor. 225 // 226 // Returns the secondary file descriptor, or -1 if the secondary file descriptor 227 // is not currently valid. 228 int PseudoTerminal::GetSecondaryFileDescriptor() const { 229 return m_secondary_fd; 230 } 231 232 // Release ownership of the primary pseudo terminal file descriptor without 233 // closing it. The destructor for this class will close the primary file 234 // descriptor if the ownership isn't released using this call and the primary 235 // file descriptor has been opened. 236 int PseudoTerminal::ReleasePrimaryFileDescriptor() { 237 // Release ownership of the primary pseudo terminal file descriptor without 238 // closing it. (the destructor for this class will close it otherwise!) 239 int fd = m_primary_fd; 240 m_primary_fd = invalid_fd; 241 return fd; 242 } 243 244 // Release ownership of the secondary pseudo terminal file descriptor without 245 // closing it. The destructor for this class will close the secondary file 246 // descriptor if the ownership isn't released using this call and the secondary 247 // file descriptor has been opened. 248 int PseudoTerminal::ReleaseSecondaryFileDescriptor() { 249 // Release ownership of the secondary pseudo terminal file descriptor without 250 // closing it (the destructor for this class will close it otherwise!) 251 int fd = m_secondary_fd; 252 m_secondary_fd = invalid_fd; 253 return fd; 254 } 255