Initial checkin of lldb code from internal Apple repo.


git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@105619 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Utility/PseudoTerminal.cpp b/source/Utility/PseudoTerminal.cpp
new file mode 100644
index 0000000..9bbecae
--- /dev/null
+++ b/source/Utility/PseudoTerminal.cpp
@@ -0,0 +1,336 @@
+//===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PseudoTerminal.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+using namespace lldb_utility;
+
+//----------------------------------------------------------------------
+// PseudoTerminal constructor
+//----------------------------------------------------------------------
+PseudoTerminal::PseudoTerminal () :
+    m_master_fd(invalid_fd),
+    m_slave_fd(invalid_fd)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// The destructor will close the master and slave file descriptors
+// if they are valid and ownwership has not been released using the
+// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor()
+// member functions.
+//----------------------------------------------------------------------
+PseudoTerminal::~PseudoTerminal ()
+{
+    CloseMasterFileDescriptor();
+    CloseSlaveFileDescriptor();
+}
+
+//----------------------------------------------------------------------
+// Close the master file descriptor if it is valid.
+//----------------------------------------------------------------------
+void
+PseudoTerminal::CloseMasterFileDescriptor ()
+{
+    if (m_master_fd >= 0)
+    {
+        ::close (m_master_fd);
+        m_master_fd = invalid_fd;
+    }
+}
+
+//----------------------------------------------------------------------
+// Close the slave file descriptor if it is valid.
+//----------------------------------------------------------------------
+void
+PseudoTerminal::CloseSlaveFileDescriptor ()
+{
+    if (m_slave_fd >= 0)
+    {
+        ::close (m_slave_fd);
+        m_slave_fd = invalid_fd;
+    }
+}
+
+//----------------------------------------------------------------------
+// Open the first available pseudo terminal with OFLAG as the
+// permissions. The file descriptor is stored in this object and can
+// be accessed with the MasterFileDescriptor() accessor. The
+// ownership of the master file descriptor can be released using
+// the ReleaseMasterFileDescriptor() accessor. If this object has
+// a valid master files descriptor when its destructor is called, it
+// will close the master file descriptor, therefore clients must
+// call ReleaseMasterFileDescriptor() if they wish to use the master
+// file descriptor after this object is out of scope or destroyed.
+//
+// RETURNS:
+//  Zero when successful, non-zero indicating an error occurred.
+//----------------------------------------------------------------------
+bool
+PseudoTerminal::OpenFirstAvailableMaster (int oflag, char *error_str, size_t error_len)
+{
+    if (error_str)
+        error_str[0] = '\0';
+
+    // Open the master side of a pseudo terminal
+    m_master_fd = ::posix_openpt (oflag);
+    if (m_master_fd < 0)
+    {
+        if (error_str)
+            ::strerror_r (errno, error_str, error_len);
+        return false;
+    }
+
+    // Grant access to the slave pseudo terminal
+    if (::grantpt (m_master_fd) < 0)
+    {
+        if (error_str)
+            ::strerror_r (errno, error_str, error_len);
+        CloseMasterFileDescriptor ();
+        return false;
+    }
+
+    // Clear the lock flag on the slave pseudo terminal
+    if (::unlockpt (m_master_fd) < 0)
+    {
+        if (error_str)
+            ::strerror_r (errno, error_str, error_len);
+        CloseMasterFileDescriptor ();
+        return false;
+    }
+
+    return true;
+}
+
+//----------------------------------------------------------------------
+// Open the slave pseudo terminal for the current master pseudo
+// terminal. A master pseudo terminal should already be valid prior to
+// calling this function (see OpenFirstAvailableMaster()).
+// The file descriptor is stored this object's member variables and can
+// be accessed via the GetSlaveFileDescriptor(), or released using the
+// ReleaseSlaveFileDescriptor() member function.
+//
+// RETURNS:
+//  Zero when successful, non-zero indicating an error occurred.
+//----------------------------------------------------------------------
+bool
+PseudoTerminal::OpenSlave (int oflag, char *error_str, size_t error_len)
+{
+    if (error_str)
+        error_str[0] = '\0';
+
+    CloseSlaveFileDescriptor();
+
+    // Open the master side of a pseudo terminal
+    const char *slave_name = GetSlaveName (error_str, error_len);
+
+    if (slave_name == NULL)
+        return false;
+
+    m_slave_fd = ::open (slave_name, oflag);
+
+    if (m_slave_fd < 0)
+    {
+        if (error_str)
+            ::strerror_r (errno, error_str, error_len);
+        return false;
+    }
+
+    return true;
+}
+
+
+
+//----------------------------------------------------------------------
+// Get the name of the slave pseudo terminal. A master pseudo terminal
+// should already be valid prior to calling this function (see
+// OpenFirstAvailableMaster()).
+//
+// RETURNS:
+//  NULL if no valid master pseudo terminal or if ptsname() fails.
+//  The name of the slave pseudo terminal as a NULL terminated C string
+//  that comes from static memory, so a copy of the string should be
+//  made as subsequent calls can change this value.
+//----------------------------------------------------------------------
+const char*
+PseudoTerminal::GetSlaveName (char *error_str, size_t error_len) const
+{
+    if (error_str)
+        error_str[0] = '\0';
+
+    if (m_master_fd < 0)
+    {
+        if (error_str)
+            ::snprintf (error_str, error_len, "%s", "master file descriptor is invalid");
+        return NULL;
+    }
+    const char *slave_name = ::ptsname (m_master_fd);
+
+    if (error_str && slave_name == NULL)
+        ::strerror_r (errno, error_str, error_len);
+
+    return slave_name;
+}
+
+
+//----------------------------------------------------------------------
+// Fork a child process and have its stdio routed to a pseudo terminal.
+//
+// In the parent process when a valid pid is returned, the master file
+// descriptor can be used as a read/write access to stdio of the
+// child process.
+//
+// In the child process the stdin/stdout/stderr will already be routed
+// to the slave pseudo terminal and the master file descriptor will be
+// closed as it is no longer needed by the child process.
+//
+// This class will close the file descriptors for the master/slave
+// when the destructor is called, so be sure to call
+// ReleaseMasterFileDescriptor() or ReleaseSlaveFileDescriptor() if any
+// file descriptors are going to be used past the lifespan of this
+// object.
+//
+// RETURNS:
+//  in the parent process: the pid of the child, or -1 if fork fails
+//  in the child process: zero
+//----------------------------------------------------------------------
+lldb::pid_t
+PseudoTerminal::Fork (char *error_str, size_t error_len)
+{
+    if (error_str)
+        error_str[0] = '\0';
+
+    pid_t pid = LLDB_INVALID_PROCESS_ID;
+    if (OpenFirstAvailableMaster (O_RDWR, error_str, error_len))
+    {
+        // Successfully opened our master pseudo terminal
+
+        pid = ::fork ();
+        if (pid < 0)
+        {
+            // Fork failed
+            if (error_str)
+            ::strerror_r (errno, error_str, error_len);
+        }
+        else if (pid == 0)
+        {
+            // Child Process
+            ::setsid();
+
+            if (OpenSlave (O_RDWR, error_str, error_len))
+            {
+                // Successfully opened slave
+                // We are done with the master in the child process so lets close it
+                CloseMasterFileDescriptor ();
+
+#if defined (TIOCSCTTY)
+                // Acquire the controlling terminal
+                if (::ioctl (m_slave_fd, TIOCSCTTY, (char *)0) < 0)
+                {
+                    if (error_str)
+                        ::strerror_r (errno, error_str, error_len);
+                }
+#endif
+                // Duplicate all stdio file descriptors to the slave pseudo terminal
+                if (::dup2 (m_slave_fd, STDIN_FILENO) != STDIN_FILENO)
+                {
+                    if (error_str && !error_str[0])
+                        ::strerror_r (errno, error_str, error_len);
+                }
+
+                if (::dup2 (m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO)
+                {
+                    if (error_str && !error_str[0])
+                        ::strerror_r (errno, error_str, error_len);
+                }
+
+                if (::dup2 (m_slave_fd, STDERR_FILENO) != STDERR_FILENO)
+                {
+                    if (error_str && !error_str[0])
+                        ::strerror_r (errno, error_str, error_len);
+                }
+            }
+        }
+        else
+        {
+            // Parent Process
+            // Do nothing and let the pid get returned!
+        }
+    }
+    return pid;
+}
+
+//----------------------------------------------------------------------
+// The master file descriptor accessor. This object retains ownership
+// of the master file descriptor when this accessor is used. Use
+// ReleaseMasterFileDescriptor() if you wish this object to release
+// ownership of the master file descriptor.
+//
+// Returns the master file descriptor, or -1 if the master file
+// descriptor is not currently valid.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::GetMasterFileDescriptor () const
+{
+    return m_master_fd;
+}
+
+//----------------------------------------------------------------------
+// The slave file descriptor accessor.
+//
+// Returns the slave file descriptor, or -1 if the slave file
+// descriptor is not currently valid.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::GetSlaveFileDescriptor () const
+{
+    return m_slave_fd;
+}
+
+//----------------------------------------------------------------------
+// Release ownership of the master pseudo terminal file descriptor
+// without closing it. The destructor for this class will close the
+// master file descriptor if the ownership isn't released using this
+// call and the master file descriptor has been opened.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::ReleaseMasterFileDescriptor ()
+{
+    // Release ownership of the master pseudo terminal file
+    // descriptor without closing it. (the destructor for this
+    // class will close it otherwise!)
+    int fd = m_master_fd;
+    m_master_fd = invalid_fd;
+    return fd;
+}
+
+//----------------------------------------------------------------------
+// Release ownership of the slave pseudo terminal file descriptor
+// without closing it. The destructor for this class will close the
+// slave file descriptor if the ownership isn't released using this
+// call and the slave file descriptor has been opened.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::ReleaseSlaveFileDescriptor ()
+{
+    // Release ownership of the slave pseudo terminal file
+    // descriptor without closing it (the destructor for this
+    // class will close it otherwise!)
+    int fd = m_slave_fd;
+    m_slave_fd = invalid_fd;
+    return fd;
+}
+