1 //===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===//
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 
12 #include "llvm/Support/Errno.h"
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #if defined(TIOCSCTTY)
18 #include <sys/ioctl.h>
19 #endif
20 
21 #include "lldb/Host/PosixApi.h"
22 
23 #if defined(__ANDROID__)
24 int posix_openpt(int flags);
25 #endif
26 
27 using namespace lldb_private;
28 
29 //----------------------------------------------------------------------
30 // Write string describing error number
31 //----------------------------------------------------------------------
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 //----------------------------------------------------------------------
38 // PseudoTerminal constructor
39 //----------------------------------------------------------------------
40 PseudoTerminal::PseudoTerminal()
41     : m_master_fd(invalid_fd), m_slave_fd(invalid_fd) {}
42 
43 //----------------------------------------------------------------------
44 // Destructor
45 //
46 // The destructor will close the master and slave file descriptors if they are
47 // valid and ownership has not been released using the
48 // ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor() member
49 // functions.
50 //----------------------------------------------------------------------
51 PseudoTerminal::~PseudoTerminal() {
52   CloseMasterFileDescriptor();
53   CloseSlaveFileDescriptor();
54 }
55 
56 //----------------------------------------------------------------------
57 // Close the master file descriptor if it is valid.
58 //----------------------------------------------------------------------
59 void PseudoTerminal::CloseMasterFileDescriptor() {
60   if (m_master_fd >= 0) {
61     ::close(m_master_fd);
62     m_master_fd = invalid_fd;
63   }
64 }
65 
66 //----------------------------------------------------------------------
67 // Close the slave file descriptor if it is valid.
68 //----------------------------------------------------------------------
69 void PseudoTerminal::CloseSlaveFileDescriptor() {
70   if (m_slave_fd >= 0) {
71     ::close(m_slave_fd);
72     m_slave_fd = invalid_fd;
73   }
74 }
75 
76 //----------------------------------------------------------------------
77 // Open the first available pseudo terminal with OFLAG as the permissions. The
78 // file descriptor is stored in this object and can be accessed with the
79 // MasterFileDescriptor() accessor. The ownership of the master file descriptor
80 // can be released using the ReleaseMasterFileDescriptor() accessor. If this
81 // object has a valid master files descriptor when its destructor is called, it
82 // will close the master file descriptor, therefore clients must call
83 // ReleaseMasterFileDescriptor() if they wish to use the master file descriptor
84 // after this object is out of scope or destroyed.
85 //
86 // RETURNS:
87 //  True when successful, false indicating an error occurred.
88 //----------------------------------------------------------------------
89 bool PseudoTerminal::OpenFirstAvailableMaster(int oflag, char *error_str,
90                                               size_t error_len) {
91   if (error_str)
92     error_str[0] = '\0';
93 
94 #if !defined(LLDB_DISABLE_POSIX)
95   // Open the master side of a pseudo terminal
96   m_master_fd = ::posix_openpt(oflag);
97   if (m_master_fd < 0) {
98     if (error_str)
99       ErrnoToStr(error_str, error_len);
100     return false;
101   }
102 
103   // Grant access to the slave pseudo terminal
104   if (::grantpt(m_master_fd) < 0) {
105     if (error_str)
106       ErrnoToStr(error_str, error_len);
107     CloseMasterFileDescriptor();
108     return false;
109   }
110 
111   // Clear the lock flag on the slave pseudo terminal
112   if (::unlockpt(m_master_fd) < 0) {
113     if (error_str)
114       ErrnoToStr(error_str, error_len);
115     CloseMasterFileDescriptor();
116     return false;
117   }
118 
119   return true;
120 #else
121   if (error_str)
122     ::snprintf(error_str, error_len, "%s", "pseudo terminal not supported");
123   return false;
124 #endif
125 }
126 
127 //----------------------------------------------------------------------
128 // Open the slave pseudo terminal for the current master pseudo terminal. A
129 // master pseudo terminal should already be valid prior to calling this
130 // function (see OpenFirstAvailableMaster()). The file descriptor is stored
131 // this object's member variables and can be accessed via the
132 // GetSlaveFileDescriptor(), or released using the ReleaseSlaveFileDescriptor()
133 // member function.
134 //
135 // RETURNS:
136 //  True when successful, false indicating an error occurred.
137 //----------------------------------------------------------------------
138 bool PseudoTerminal::OpenSlave(int oflag, char *error_str, size_t error_len) {
139   if (error_str)
140     error_str[0] = '\0';
141 
142   CloseSlaveFileDescriptor();
143 
144   // Open the master side of a pseudo terminal
145   const char *slave_name = GetSlaveName(error_str, error_len);
146 
147   if (slave_name == nullptr)
148     return false;
149 
150   m_slave_fd = llvm::sys::RetryAfterSignal(-1, ::open, slave_name, oflag);
151 
152   if (m_slave_fd < 0) {
153     if (error_str)
154       ErrnoToStr(error_str, error_len);
155     return false;
156   }
157 
158   return true;
159 }
160 
161 //----------------------------------------------------------------------
162 // Get the name of the slave pseudo terminal. A master pseudo terminal should
163 // already be valid prior to calling this function (see
164 // OpenFirstAvailableMaster()).
165 //
166 // RETURNS:
167 //  NULL if no valid master pseudo terminal or if ptsname() fails.
168 //  The name of the slave pseudo terminal as a NULL terminated C string
169 //  that comes from static memory, so a copy of the string should be
170 //  made as subsequent calls can change this value.
171 //----------------------------------------------------------------------
172 const char *PseudoTerminal::GetSlaveName(char *error_str,
173                                          size_t error_len) const {
174   if (error_str)
175     error_str[0] = '\0';
176 
177   if (m_master_fd < 0) {
178     if (error_str)
179       ::snprintf(error_str, error_len, "%s",
180                  "master file descriptor is invalid");
181     return nullptr;
182   }
183   const char *slave_name = ::ptsname(m_master_fd);
184 
185   if (error_str && slave_name == nullptr)
186     ErrnoToStr(error_str, error_len);
187 
188   return slave_name;
189 }
190 
191 //----------------------------------------------------------------------
192 // Fork a child process and have its stdio routed to a pseudo terminal.
193 //
194 // In the parent process when a valid pid is returned, the master file
195 // descriptor can be used as a read/write access to stdio of the child process.
196 //
197 // In the child process the stdin/stdout/stderr will already be routed to the
198 // slave pseudo terminal and the master file descriptor will be closed as it is
199 // no longer needed by the child process.
200 //
201 // This class will close the file descriptors for the master/slave when the
202 // destructor is called, so be sure to call ReleaseMasterFileDescriptor() or
203 // ReleaseSlaveFileDescriptor() if any file descriptors are going to be used
204 // past the lifespan of this object.
205 //
206 // RETURNS:
207 //  in the parent process: the pid of the child, or -1 if fork fails
208 //  in the child process: zero
209 //----------------------------------------------------------------------
210 lldb::pid_t PseudoTerminal::Fork(char *error_str, size_t error_len) {
211   if (error_str)
212     error_str[0] = '\0';
213   pid_t pid = LLDB_INVALID_PROCESS_ID;
214 #if !defined(LLDB_DISABLE_POSIX)
215   int flags = O_RDWR;
216   flags |= O_CLOEXEC;
217   if (OpenFirstAvailableMaster(flags, error_str, error_len)) {
218     // Successfully opened our master pseudo terminal
219 
220     pid = ::fork();
221     if (pid < 0) {
222       // Fork failed
223       if (error_str)
224         ErrnoToStr(error_str, error_len);
225     } else if (pid == 0) {
226       // Child Process
227       ::setsid();
228 
229       if (OpenSlave(O_RDWR, error_str, error_len)) {
230         // Successfully opened slave
231 
232         // Master FD should have O_CLOEXEC set, but let's close it just in
233         // case...
234         CloseMasterFileDescriptor();
235 
236 #if defined(TIOCSCTTY)
237         // Acquire the controlling terminal
238         if (::ioctl(m_slave_fd, TIOCSCTTY, (char *)0) < 0) {
239           if (error_str)
240             ErrnoToStr(error_str, error_len);
241         }
242 #endif
243         // Duplicate all stdio file descriptors to the slave pseudo terminal
244         if (::dup2(m_slave_fd, STDIN_FILENO) != STDIN_FILENO) {
245           if (error_str && !error_str[0])
246             ErrnoToStr(error_str, error_len);
247         }
248 
249         if (::dup2(m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) {
250           if (error_str && !error_str[0])
251             ErrnoToStr(error_str, error_len);
252         }
253 
254         if (::dup2(m_slave_fd, STDERR_FILENO) != STDERR_FILENO) {
255           if (error_str && !error_str[0])
256             ErrnoToStr(error_str, error_len);
257         }
258       }
259     } else {
260       // Parent Process
261       // Do nothing and let the pid get returned!
262     }
263   }
264 #endif
265   return pid;
266 }
267 
268 //----------------------------------------------------------------------
269 // The master file descriptor accessor. This object retains ownership of the
270 // master file descriptor when this accessor is used. Use
271 // ReleaseMasterFileDescriptor() if you wish this object to release ownership
272 // of the master file descriptor.
273 //
274 // Returns the master file descriptor, or -1 if the master file descriptor is
275 // not currently valid.
276 //----------------------------------------------------------------------
277 int PseudoTerminal::GetMasterFileDescriptor() const { return m_master_fd; }
278 
279 //----------------------------------------------------------------------
280 // The slave file descriptor accessor.
281 //
282 // Returns the slave file descriptor, or -1 if the slave file descriptor is not
283 // currently valid.
284 //----------------------------------------------------------------------
285 int PseudoTerminal::GetSlaveFileDescriptor() const { return m_slave_fd; }
286 
287 //----------------------------------------------------------------------
288 // Release ownership of the master pseudo terminal file descriptor without
289 // closing it. The destructor for this class will close the master file
290 // descriptor if the ownership isn't released using this call and the master
291 // file descriptor has been opened.
292 //----------------------------------------------------------------------
293 int PseudoTerminal::ReleaseMasterFileDescriptor() {
294   // Release ownership of the master pseudo terminal file descriptor without
295   // closing it. (the destructor for this class will close it otherwise!)
296   int fd = m_master_fd;
297   m_master_fd = invalid_fd;
298   return fd;
299 }
300 
301 //----------------------------------------------------------------------
302 // Release ownership of the slave pseudo terminal file descriptor without
303 // closing it. The destructor for this class will close the slave file
304 // descriptor if the ownership isn't released using this call and the slave
305 // file descriptor has been opened.
306 //----------------------------------------------------------------------
307 int PseudoTerminal::ReleaseSlaveFileDescriptor() {
308   // Release ownership of the slave pseudo terminal file descriptor without
309   // closing it (the destructor for this class will close it otherwise!)
310   int fd = m_slave_fd;
311   m_slave_fd = invalid_fd;
312   return fd;
313 }
314