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