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__)
30int posix_openpt(int flags);
31#endif
32
33using 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
94llvm::Error PseudoTerminal::OpenSecondary(int oflag) {
96
97 std::string name = GetSecondaryName();
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__)
107static 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 {
131 }
132#endif
133#else
135#endif
136}
137
138llvm::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}
static std::string use_ptsname(int fd)
PseudoTerminal()
Default constructor.
int m_secondary_fd
The file descriptor for the secondary.
int ReleaseSecondaryFileDescriptor()
Release the secondary file descriptor.
llvm::Error OpenFirstAvailablePrimary(int oflag)
Open the first available pseudo terminal.
llvm::Error OpenSecondary(int oflag)
Open the secondary for the current primary pseudo terminal.
void ClosePrimaryFileDescriptor()
Close the primary file descriptor if it is valid.
int m_primary_fd
The file descriptor for the primary.
llvm::Expected< lldb::pid_t > Fork()
Fork a child process that uses pseudo terminals for its stdio.
int GetPrimaryFileDescriptor() const
The primary file descriptor accessor.
int ReleasePrimaryFileDescriptor()
Release the primary file descriptor.
std::string GetSecondaryName() const
Get the name of the secondary pseudo terminal.
void CloseSecondaryFileDescriptor()
Close the secondary file descriptor if it is valid.
int GetSecondaryFileDescriptor() const
The secondary file descriptor accessor.
@ invalid_fd
Invalid file descriptor value.
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
char * ptsname(int fd)
int grantpt(int fd)
pid_t setsid(void)
int posix_openpt(int flag)
pid_t fork(void)
int unlockpt(int fd)
#define PATH_MAX