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