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