PseudoTerminal.cpp revision 344779
1317027Sdim//===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===//
2317027Sdim//
3317027Sdim//                     The LLVM Compiler Infrastructure
4317027Sdim//
5317027Sdim// This file is distributed under the University of Illinois Open Source
6317027Sdim// License. See LICENSE.TXT for details.
7317027Sdim//
8317027Sdim//===----------------------------------------------------------------------===//
9317027Sdim
10317027Sdim#include "lldb/Host/PseudoTerminal.h"
11317027Sdim#include "lldb/Host/Config.h"
12317027Sdim
13344779Sdim#include "llvm/Support/Errno.h"
14344779Sdim
15317027Sdim#include <stdio.h>
16317027Sdim#include <stdlib.h>
17317027Sdim#include <string.h>
18317027Sdim#if defined(TIOCSCTTY)
19317027Sdim#include <sys/ioctl.h>
20317027Sdim#endif
21317027Sdim
22317027Sdim#include "lldb/Host/PosixApi.h"
23317027Sdim
24317027Sdim#if defined(__ANDROID__)
25317027Sdimint posix_openpt(int flags);
26317027Sdim#endif
27317027Sdim
28327952Sdimusing namespace lldb_private;
29317027Sdim
30317027Sdim//----------------------------------------------------------------------
31344779Sdim// Write string describing error number
32344779Sdim//----------------------------------------------------------------------
33344779Sdimstatic void ErrnoToStr(char *error_str, size_t error_len) {
34344779Sdim  std::string strerror = llvm::sys::StrError();
35344779Sdim  ::snprintf(error_str, error_len, "%s", strerror.c_str());
36344779Sdim}
37344779Sdim
38344779Sdim//----------------------------------------------------------------------
39317027Sdim// PseudoTerminal constructor
40317027Sdim//----------------------------------------------------------------------
41317027SdimPseudoTerminal::PseudoTerminal()
42317027Sdim    : m_master_fd(invalid_fd), m_slave_fd(invalid_fd) {}
43317027Sdim
44317027Sdim//----------------------------------------------------------------------
45317027Sdim// Destructor
46317027Sdim//
47341825Sdim// The destructor will close the master and slave file descriptors if they are
48341825Sdim// valid and ownership has not been released using the
49341825Sdim// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor() member
50341825Sdim// functions.
51317027Sdim//----------------------------------------------------------------------
52317027SdimPseudoTerminal::~PseudoTerminal() {
53317027Sdim  CloseMasterFileDescriptor();
54317027Sdim  CloseSlaveFileDescriptor();
55317027Sdim}
56317027Sdim
57317027Sdim//----------------------------------------------------------------------
58317027Sdim// Close the master file descriptor if it is valid.
59317027Sdim//----------------------------------------------------------------------
60317027Sdimvoid PseudoTerminal::CloseMasterFileDescriptor() {
61317027Sdim  if (m_master_fd >= 0) {
62317027Sdim    ::close(m_master_fd);
63317027Sdim    m_master_fd = invalid_fd;
64317027Sdim  }
65317027Sdim}
66317027Sdim
67317027Sdim//----------------------------------------------------------------------
68317027Sdim// Close the slave file descriptor if it is valid.
69317027Sdim//----------------------------------------------------------------------
70317027Sdimvoid PseudoTerminal::CloseSlaveFileDescriptor() {
71317027Sdim  if (m_slave_fd >= 0) {
72317027Sdim    ::close(m_slave_fd);
73317027Sdim    m_slave_fd = invalid_fd;
74317027Sdim  }
75317027Sdim}
76317027Sdim
77317027Sdim//----------------------------------------------------------------------
78341825Sdim// Open the first available pseudo terminal with OFLAG as the permissions. The
79341825Sdim// file descriptor is stored in this object and can be accessed with the
80341825Sdim// MasterFileDescriptor() accessor. The ownership of the master file descriptor
81341825Sdim// can be released using the ReleaseMasterFileDescriptor() accessor. If this
82341825Sdim// object has a valid master files descriptor when its destructor is called, it
83341825Sdim// will close the master file descriptor, therefore clients must call
84341825Sdim// ReleaseMasterFileDescriptor() if they wish to use the master file descriptor
85341825Sdim// after this object is out of scope or destroyed.
86317027Sdim//
87317027Sdim// RETURNS:
88317027Sdim//  True when successful, false indicating an error occurred.
89317027Sdim//----------------------------------------------------------------------
90317027Sdimbool PseudoTerminal::OpenFirstAvailableMaster(int oflag, char *error_str,
91317027Sdim                                              size_t error_len) {
92317027Sdim  if (error_str)
93317027Sdim    error_str[0] = '\0';
94317027Sdim
95317027Sdim#if !defined(LLDB_DISABLE_POSIX)
96317027Sdim  // Open the master side of a pseudo terminal
97317027Sdim  m_master_fd = ::posix_openpt(oflag);
98317027Sdim  if (m_master_fd < 0) {
99317027Sdim    if (error_str)
100344779Sdim      ErrnoToStr(error_str, error_len);
101317027Sdim    return false;
102317027Sdim  }
103317027Sdim
104317027Sdim  // Grant access to the slave pseudo terminal
105317027Sdim  if (::grantpt(m_master_fd) < 0) {
106317027Sdim    if (error_str)
107344779Sdim      ErrnoToStr(error_str, error_len);
108317027Sdim    CloseMasterFileDescriptor();
109317027Sdim    return false;
110317027Sdim  }
111317027Sdim
112317027Sdim  // Clear the lock flag on the slave pseudo terminal
113317027Sdim  if (::unlockpt(m_master_fd) < 0) {
114317027Sdim    if (error_str)
115344779Sdim      ErrnoToStr(error_str, error_len);
116317027Sdim    CloseMasterFileDescriptor();
117317027Sdim    return false;
118317027Sdim  }
119317027Sdim
120317027Sdim  return true;
121317027Sdim#else
122317027Sdim  if (error_str)
123317027Sdim    ::snprintf(error_str, error_len, "%s", "pseudo terminal not supported");
124317027Sdim  return false;
125317027Sdim#endif
126317027Sdim}
127317027Sdim
128317027Sdim//----------------------------------------------------------------------
129341825Sdim// Open the slave pseudo terminal for the current master pseudo terminal. A
130341825Sdim// master pseudo terminal should already be valid prior to calling this
131341825Sdim// function (see OpenFirstAvailableMaster()). The file descriptor is stored
132341825Sdim// this object's member variables and can be accessed via the
133341825Sdim// GetSlaveFileDescriptor(), or released using the ReleaseSlaveFileDescriptor()
134341825Sdim// member function.
135317027Sdim//
136317027Sdim// RETURNS:
137317027Sdim//  True when successful, false indicating an error occurred.
138317027Sdim//----------------------------------------------------------------------
139317027Sdimbool PseudoTerminal::OpenSlave(int oflag, char *error_str, size_t error_len) {
140317027Sdim  if (error_str)
141317027Sdim    error_str[0] = '\0';
142317027Sdim
143317027Sdim  CloseSlaveFileDescriptor();
144317027Sdim
145317027Sdim  // Open the master side of a pseudo terminal
146317027Sdim  const char *slave_name = GetSlaveName(error_str, error_len);
147317027Sdim
148317027Sdim  if (slave_name == nullptr)
149317027Sdim    return false;
150317027Sdim
151317027Sdim  m_slave_fd = ::open(slave_name, oflag);
152317027Sdim
153317027Sdim  if (m_slave_fd < 0) {
154317027Sdim    if (error_str)
155344779Sdim      ErrnoToStr(error_str, error_len);
156317027Sdim    return false;
157317027Sdim  }
158317027Sdim
159317027Sdim  return true;
160317027Sdim}
161317027Sdim
162317027Sdim//----------------------------------------------------------------------
163341825Sdim// Get the name of the slave pseudo terminal. A master pseudo terminal should
164341825Sdim// already be valid prior to calling this function (see
165317027Sdim// OpenFirstAvailableMaster()).
166317027Sdim//
167317027Sdim// RETURNS:
168317027Sdim//  NULL if no valid master pseudo terminal or if ptsname() fails.
169317027Sdim//  The name of the slave pseudo terminal as a NULL terminated C string
170317027Sdim//  that comes from static memory, so a copy of the string should be
171317027Sdim//  made as subsequent calls can change this value.
172317027Sdim//----------------------------------------------------------------------
173317027Sdimconst char *PseudoTerminal::GetSlaveName(char *error_str,
174317027Sdim                                         size_t error_len) const {
175317027Sdim  if (error_str)
176317027Sdim    error_str[0] = '\0';
177317027Sdim
178317027Sdim  if (m_master_fd < 0) {
179317027Sdim    if (error_str)
180317027Sdim      ::snprintf(error_str, error_len, "%s",
181317027Sdim                 "master file descriptor is invalid");
182317027Sdim    return nullptr;
183317027Sdim  }
184317027Sdim  const char *slave_name = ::ptsname(m_master_fd);
185317027Sdim
186317027Sdim  if (error_str && slave_name == nullptr)
187344779Sdim    ErrnoToStr(error_str, error_len);
188317027Sdim
189317027Sdim  return slave_name;
190317027Sdim}
191317027Sdim
192317027Sdim//----------------------------------------------------------------------
193317027Sdim// Fork a child process and have its stdio routed to a pseudo terminal.
194317027Sdim//
195317027Sdim// In the parent process when a valid pid is returned, the master file
196341825Sdim// descriptor can be used as a read/write access to stdio of the child process.
197317027Sdim//
198341825Sdim// In the child process the stdin/stdout/stderr will already be routed to the
199341825Sdim// slave pseudo terminal and the master file descriptor will be closed as it is
200341825Sdim// no longer needed by the child process.
201317027Sdim//
202341825Sdim// This class will close the file descriptors for the master/slave when the
203341825Sdim// destructor is called, so be sure to call ReleaseMasterFileDescriptor() or
204341825Sdim// ReleaseSlaveFileDescriptor() if any file descriptors are going to be used
205341825Sdim// past the lifespan of this object.
206317027Sdim//
207317027Sdim// RETURNS:
208317027Sdim//  in the parent process: the pid of the child, or -1 if fork fails
209317027Sdim//  in the child process: zero
210317027Sdim//----------------------------------------------------------------------
211317027Sdimlldb::pid_t PseudoTerminal::Fork(char *error_str, size_t error_len) {
212317027Sdim  if (error_str)
213317027Sdim    error_str[0] = '\0';
214317027Sdim  pid_t pid = LLDB_INVALID_PROCESS_ID;
215317027Sdim#if !defined(LLDB_DISABLE_POSIX)
216317027Sdim  int flags = O_RDWR;
217317027Sdim  flags |= O_CLOEXEC;
218317027Sdim  if (OpenFirstAvailableMaster(flags, error_str, error_len)) {
219317027Sdim    // Successfully opened our master pseudo terminal
220317027Sdim
221317027Sdim    pid = ::fork();
222317027Sdim    if (pid < 0) {
223317027Sdim      // Fork failed
224317027Sdim      if (error_str)
225344779Sdim        ErrnoToStr(error_str, error_len);
226317027Sdim    } else if (pid == 0) {
227317027Sdim      // Child Process
228317027Sdim      ::setsid();
229317027Sdim
230317027Sdim      if (OpenSlave(O_RDWR, error_str, error_len)) {
231317027Sdim        // Successfully opened slave
232317027Sdim
233317027Sdim        // Master FD should have O_CLOEXEC set, but let's close it just in
234317027Sdim        // case...
235317027Sdim        CloseMasterFileDescriptor();
236317027Sdim
237317027Sdim#if defined(TIOCSCTTY)
238317027Sdim        // Acquire the controlling terminal
239317027Sdim        if (::ioctl(m_slave_fd, TIOCSCTTY, (char *)0) < 0) {
240317027Sdim          if (error_str)
241344779Sdim            ErrnoToStr(error_str, error_len);
242317027Sdim        }
243317027Sdim#endif
244317027Sdim        // Duplicate all stdio file descriptors to the slave pseudo terminal
245317027Sdim        if (::dup2(m_slave_fd, STDIN_FILENO) != STDIN_FILENO) {
246317027Sdim          if (error_str && !error_str[0])
247344779Sdim            ErrnoToStr(error_str, error_len);
248317027Sdim        }
249317027Sdim
250317027Sdim        if (::dup2(m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) {
251317027Sdim          if (error_str && !error_str[0])
252344779Sdim            ErrnoToStr(error_str, error_len);
253317027Sdim        }
254317027Sdim
255317027Sdim        if (::dup2(m_slave_fd, STDERR_FILENO) != STDERR_FILENO) {
256317027Sdim          if (error_str && !error_str[0])
257344779Sdim            ErrnoToStr(error_str, error_len);
258317027Sdim        }
259317027Sdim      }
260317027Sdim    } else {
261317027Sdim      // Parent Process
262317027Sdim      // Do nothing and let the pid get returned!
263317027Sdim    }
264317027Sdim  }
265317027Sdim#endif
266317027Sdim  return pid;
267317027Sdim}
268317027Sdim
269317027Sdim//----------------------------------------------------------------------
270341825Sdim// The master file descriptor accessor. This object retains ownership of the
271341825Sdim// master file descriptor when this accessor is used. Use
272341825Sdim// ReleaseMasterFileDescriptor() if you wish this object to release ownership
273341825Sdim// of the master file descriptor.
274317027Sdim//
275341825Sdim// Returns the master file descriptor, or -1 if the master file descriptor is
276341825Sdim// not currently valid.
277317027Sdim//----------------------------------------------------------------------
278317027Sdimint PseudoTerminal::GetMasterFileDescriptor() const { return m_master_fd; }
279317027Sdim
280317027Sdim//----------------------------------------------------------------------
281317027Sdim// The slave file descriptor accessor.
282317027Sdim//
283341825Sdim// Returns the slave file descriptor, or -1 if the slave file descriptor is not
284341825Sdim// currently valid.
285317027Sdim//----------------------------------------------------------------------
286317027Sdimint PseudoTerminal::GetSlaveFileDescriptor() const { return m_slave_fd; }
287317027Sdim
288317027Sdim//----------------------------------------------------------------------
289341825Sdim// Release ownership of the master pseudo terminal file descriptor without
290341825Sdim// closing it. The destructor for this class will close the master file
291341825Sdim// descriptor if the ownership isn't released using this call and the master
292341825Sdim// file descriptor has been opened.
293317027Sdim//----------------------------------------------------------------------
294317027Sdimint PseudoTerminal::ReleaseMasterFileDescriptor() {
295341825Sdim  // Release ownership of the master pseudo terminal file descriptor without
296341825Sdim  // closing it. (the destructor for this class will close it otherwise!)
297317027Sdim  int fd = m_master_fd;
298317027Sdim  m_master_fd = invalid_fd;
299317027Sdim  return fd;
300317027Sdim}
301317027Sdim
302317027Sdim//----------------------------------------------------------------------
303341825Sdim// Release ownership of the slave pseudo terminal file descriptor without
304341825Sdim// closing it. The destructor for this class will close the slave file
305341825Sdim// descriptor if the ownership isn't released using this call and the slave
306341825Sdim// file descriptor has been opened.
307317027Sdim//----------------------------------------------------------------------
308317027Sdimint PseudoTerminal::ReleaseSlaveFileDescriptor() {
309341825Sdim  // Release ownership of the slave pseudo terminal file descriptor without
310341825Sdim  // closing it (the destructor for this class will close it otherwise!)
311317027Sdim  int fd = m_slave_fd;
312317027Sdim  m_slave_fd = invalid_fd;
313317027Sdim  return fd;
314317027Sdim}
315