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