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