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