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