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
posix_openpt(int flag)23 int posix_openpt(int flag) { return 0; }
24
strerror_r(int errnum,char * buf,size_t buflen)25 int strerror_r(int errnum, char *buf, size_t buflen) { return 0; }
26
unlockpt(int fd)27 int unlockpt(int fd) { return 0; }
grantpt(int fd)28 int grantpt(int fd) { return 0; }
ptsname(int fd)29 char *ptsname(int fd) { return 0; }
30
fork(void)31 pid_t fork(void) { return 0; }
setsid(void)32 pid_t setsid(void) { return 0; }
33 #endif
34
35 using namespace lldb_utility;
36
37 //----------------------------------------------------------------------
38 // PseudoTerminal constructor
39 //----------------------------------------------------------------------
PseudoTerminal()40 PseudoTerminal::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 //----------------------------------------------------------------------
~PseudoTerminal()54 PseudoTerminal::~PseudoTerminal ()
55 {
56 CloseMasterFileDescriptor();
57 CloseSlaveFileDescriptor();
58 }
59
60 //----------------------------------------------------------------------
61 // Close the master file descriptor if it is valid.
62 //----------------------------------------------------------------------
63 void
CloseMasterFileDescriptor()64 PseudoTerminal::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 //----------------------------------------------------------------------
76 void
CloseSlaveFileDescriptor()77 PseudoTerminal::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 //----------------------------------------------------------------------
100 bool
OpenFirstAvailableMaster(int oflag,char * error_str,size_t error_len)101 PseudoTerminal::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 //----------------------------------------------------------------------
147 bool
OpenSlave(int oflag,char * error_str,size_t error_len)148 PseudoTerminal::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 //----------------------------------------------------------------------
186 const char*
GetSlaveName(char * error_str,size_t error_len) const187 PseudoTerminal::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 //----------------------------------------------------------------------
228 lldb::pid_t
Fork(char * error_str,size_t error_len)229 PseudoTerminal::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 //----------------------------------------------------------------------
303 int
GetMasterFileDescriptor() const304 PseudoTerminal::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 //----------------------------------------------------------------------
315 int
GetSlaveFileDescriptor() const316 PseudoTerminal::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 //----------------------------------------------------------------------
327 int
ReleaseMasterFileDescriptor()328 PseudoTerminal::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 //----------------------------------------------------------------------
344 int
ReleaseSlaveFileDescriptor()345 PseudoTerminal::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