LLDB  mainline
PseudoTerminal.cpp
Go to the documentation of this file.
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 
10 #include "lldb/Host/Config.h"
11 #include "llvm/Support/Errc.h"
12 #include "llvm/Support/Errno.h"
13 #include <cassert>
14 #include <climits>
15 #include <cstdio>
16 #include <cstdlib>
17 #include <cstring>
18 #include <mutex>
19 #if defined(TIOCSCTTY)
20 #include <sys/ioctl.h>
21 #endif
22 
23 #include "lldb/Host/PosixApi.h"
24 
25 #if defined(__APPLE__)
26 #include <Availability.h>
27 #endif
28 
29 #if defined(__ANDROID__)
30 int posix_openpt(int flags);
31 #endif
32 
33 using namespace lldb_private;
34 
35 // PseudoTerminal constructor
37 
38 // Destructor
39 //
40 // The destructor will close the primary and secondary file descriptors if they
41 // are valid and ownership has not been released using the
42 // ReleasePrimaryFileDescriptor() or the ReleaseSaveFileDescriptor() member
43 // functions.
47 }
48 
49 // Close the primary file descriptor if it is valid.
51  if (m_primary_fd >= 0) {
52  ::close(m_primary_fd);
54  }
55 }
56 
57 // Close the secondary file descriptor if it is valid.
59  if (m_secondary_fd >= 0) {
60  ::close(m_secondary_fd);
62  }
63 }
64 
66 #if LLDB_ENABLE_POSIX
67  // Open the primary side of a pseudo terminal
69  if (m_primary_fd < 0) {
70  return llvm::errorCodeToError(
71  std::error_code(errno, std::generic_category()));
72  }
73 
74  // Grant access to the secondary pseudo terminal
75  if (::grantpt(m_primary_fd) < 0) {
76  std::error_code EC(errno, std::generic_category());
78  return llvm::errorCodeToError(EC);
79  }
80 
81  // Clear the lock flag on the secondary pseudo terminal
82  if (::unlockpt(m_primary_fd) < 0) {
83  std::error_code EC(errno, std::generic_category());
85  return llvm::errorCodeToError(EC);
86  }
87 
88  return llvm::Error::success();
89 #else
90  return llvm::errorCodeToError(llvm::errc::not_supported);
91 #endif
92 }
93 
96 
98  m_secondary_fd = llvm::sys::RetryAfterSignal(-1, ::open, name.c_str(), oflag);
99  if (m_secondary_fd >= 0)
100  return llvm::Error::success();
101 
102  return llvm::errorCodeToError(
103  std::error_code(errno, std::generic_category()));
104 }
105 
106 #if !HAVE_PTSNAME_R || defined(__APPLE__)
107 static std::string use_ptsname(int fd) {
108  static std::mutex mutex;
109  std::lock_guard<std::mutex> guard(mutex);
110  const char *r = ptsname(fd);
111  assert(r != nullptr);
112  return r;
113 }
114 #endif
115 
117  assert(m_primary_fd >= 0);
118 #if HAVE_PTSNAME_R
119 #if defined(__APPLE__)
120  if (__builtin_available(macos 10.13.4, iOS 11.3, tvOS 11.3, watchOS 4.4, *)) {
121 #endif
122  char buf[PATH_MAX];
123  buf[0] = '\0';
124  int r = ptsname_r(m_primary_fd, buf, sizeof(buf));
125  (void)r;
126  assert(r == 0);
127  return buf;
128 #if defined(__APPLE__)
129  } else {
130  return use_ptsname(m_primary_fd);
131  }
132 #endif
133 #else
134  return use_ptsname(m_primary_fd);
135 #endif
136 }
137 
138 llvm::Expected<lldb::pid_t> PseudoTerminal::Fork() {
139 #if LLDB_ENABLE_POSIX
140  if (llvm::Error Err = OpenFirstAvailablePrimary(O_RDWR | O_CLOEXEC))
141  return std::move(Err);
142 
143  pid_t pid = ::fork();
144  if (pid < 0) {
145  return llvm::errorCodeToError(
146  std::error_code(errno, std::generic_category()));
147  }
148  if (pid > 0) {
149  // Parent process.
150  return pid;
151  }
152 
153  // Child Process
154  ::setsid();
155 
156  if (llvm::Error Err = OpenSecondary(O_RDWR))
157  return std::move(Err);
158 
159  // Primary FD should have O_CLOEXEC set, but let's close it just in
160  // case...
162 
163 #if defined(TIOCSCTTY)
164  // Acquire the controlling terminal
165  if (::ioctl(m_secondary_fd, TIOCSCTTY, (char *)0) < 0) {
166  return llvm::errorCodeToError(
167  std::error_code(errno, std::generic_category()));
168  }
169 #endif
170  // Duplicate all stdio file descriptors to the secondary pseudo terminal
171  for (int fd : {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}) {
172  if (::dup2(m_secondary_fd, fd) != fd) {
173  return llvm::errorCodeToError(
174  std::error_code(errno, std::generic_category()));
175  }
176  }
177 #endif
178  return 0;
179 }
180 
181 // The primary file descriptor accessor. This object retains ownership of the
182 // primary file descriptor when this accessor is used. Use
183 // ReleasePrimaryFileDescriptor() if you wish this object to release ownership
184 // of the primary file descriptor.
185 //
186 // Returns the primary file descriptor, or -1 if the primary file descriptor is
187 // not currently valid.
189 
190 // The secondary file descriptor accessor.
191 //
192 // Returns the secondary file descriptor, or -1 if the secondary file descriptor
193 // is not currently valid.
195  return m_secondary_fd;
196 }
197 
198 // Release ownership of the primary pseudo terminal file descriptor without
199 // closing it. The destructor for this class will close the primary file
200 // descriptor if the ownership isn't released using this call and the primary
201 // file descriptor has been opened.
203  // Release ownership of the primary pseudo terminal file descriptor without
204  // closing it. (the destructor for this class will close it otherwise!)
205  int fd = m_primary_fd;
207  return fd;
208 }
209 
210 // Release ownership of the secondary pseudo terminal file descriptor without
211 // closing it. The destructor for this class will close the secondary file
212 // descriptor if the ownership isn't released using this call and the secondary
213 // file descriptor has been opened.
215  // Release ownership of the secondary pseudo terminal file descriptor without
216  // closing it (the destructor for this class will close it otherwise!)
217  int fd = m_secondary_fd;
219  return fd;
220 }
lldb_private::PseudoTerminal::ReleaseSecondaryFileDescriptor
int ReleaseSecondaryFileDescriptor()
Release the secondary file descriptor.
Definition: PseudoTerminal.cpp:214
lldb_private::PseudoTerminal::m_secondary_fd
int m_secondary_fd
The file descriptor for the secondary.
Definition: PseudoTerminal.h:179
lldb_private::PseudoTerminal::invalid_fd
@ invalid_fd
Invalid file descriptor value.
Definition: PseudoTerminal.h:27
lldb_private::PseudoTerminal::GetPrimaryFileDescriptor
int GetPrimaryFileDescriptor() const
The primary file descriptor accessor.
Definition: PseudoTerminal.cpp:188
unlockpt
int unlockpt(int fd)
Definition: windows/PosixApi.h:92
lldb_private::PseudoTerminal::m_primary_fd
int m_primary_fd
The file descriptor for the primary.
Definition: PseudoTerminal.h:178
lldb_private::PseudoTerminal::GetSecondaryFileDescriptor
int GetSecondaryFileDescriptor() const
The secondary file descriptor accessor.
Definition: PseudoTerminal.cpp:194
lldb_private::PseudoTerminal::OpenFirstAvailablePrimary
llvm::Error OpenFirstAvailablePrimary(int oflag)
Open the first available pseudo terminal.
Definition: PseudoTerminal.cpp:65
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
lldb_private::PseudoTerminal::OpenSecondary
llvm::Error OpenSecondary(int oflag)
Open the secondary for the current primary pseudo terminal.
Definition: PseudoTerminal.cpp:94
lldb_private::PseudoTerminal::ClosePrimaryFileDescriptor
void ClosePrimaryFileDescriptor()
Close the primary file descriptor if it is valid.
Definition: PseudoTerminal.cpp:50
lldb_private::PseudoTerminal::GetSecondaryName
std::string GetSecondaryName() const
Get the name of the secondary pseudo terminal.
Definition: PseudoTerminal.cpp:116
posix_openpt
int posix_openpt(int flag)
Definition: windows/PosixApi.h:90
lldb_private::PseudoTerminal::ReleasePrimaryFileDescriptor
int ReleasePrimaryFileDescriptor()
Release the primary file descriptor.
Definition: PseudoTerminal.cpp:202
lldb_private::PseudoTerminal::CloseSecondaryFileDescriptor
void CloseSecondaryFileDescriptor()
Close the secondary file descriptor if it is valid.
Definition: PseudoTerminal.cpp:58
lldb_private::PseudoTerminal::PseudoTerminal
PseudoTerminal()
Default constructor.
setsid
pid_t setsid(void)
Definition: windows/PosixApi.h:97
lldb::pid_t
uint64_t pid_t
Definition: lldb-types.h:85
lldb_private::PseudoTerminal::~PseudoTerminal
~PseudoTerminal()
Destructor.
Definition: PseudoTerminal.cpp:44
PseudoTerminal.h
lldb_private::PseudoTerminal::Fork
llvm::Expected< lldb::pid_t > Fork()
Fork a child process that uses pseudo terminals for its stdio.
Definition: PseudoTerminal.cpp:138
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
ptsname
char * ptsname(int fd)
Definition: windows/PosixApi.h:94
fork
pid_t fork(void)
Definition: windows/PosixApi.h:96
Error
llvm::Error Error
Definition: UdtRecordCompleter.cpp:30
PosixApi.h
grantpt
int grantpt(int fd)
Definition: windows/PosixApi.h:93
PATH_MAX
#define PATH_MAX
Definition: windows/PosixApi.h:25
use_ptsname
static std::string use_ptsname(int fd)
Definition: PseudoTerminal.cpp:107