Home | History | Annotate | Download | only in Utility
      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 //----------------------------------------------------------------------
     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 //----------------------------------------------------------------------
     39 PseudoTerminal::~PseudoTerminal ()
     40 {
     41     CloseMasterFileDescriptor();
     42     CloseSlaveFileDescriptor();
     43 }
     44 
     45 //----------------------------------------------------------------------
     46 // Close the master file descriptor if it is valid.
     47 //----------------------------------------------------------------------
     48 void
     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
     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
     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
    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*
    172 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
    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
    289 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
    301 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
    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
    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