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